package refactoring

git-svn-id: https://osmand.googlecode.com/svn/trunk@602 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-10-28 16:57:58 +00:00
parent f3758d384c
commit d1f0dd612d
93 changed files with 40994 additions and 139 deletions

View file

@ -7,6 +7,5 @@
<classpathentry kind="lib" path="lib/commons-logging-1.1.1.jar"/>
<classpathentry kind="lib" path="lib/junidecode-0.1.jar"/>
<classpathentry kind="lib" path="lib/json-20090211.jar"/>
<classpathentry kind="lib" path="lib/osm-pbf.jar" sourcepath="/OsmPdb"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,10 @@
<!-- build JAR libraty -->
<project name="OsmPDB" default="build" basedir=".">
<target name="build" >
<exec dir="." executable="protoc">
<arg value="src/osmand_odb.proto"/>
<arg value="--java_out=./src/"/>
</exec>
</target>
</project>

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,708 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.InputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A partial implementation of the {@link Message} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessage extends AbstractMessageLite
implements Message {
@SuppressWarnings("unchecked")
public boolean isInitialized() {
// Check that all required fields are present.
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
if (field.isRequired()) {
if (!hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
for (final Message element : (List<Message>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
if (!((Message) entry.getValue()).isInitialized()) {
return false;
}
}
}
}
return true;
}
@Override
public final String toString() {
return TextFormat.printToString(this);
}
public void writeTo(final CodedOutputStream output) throws IOException {
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
output.writeMessageSetExtension(field.getNumber(), (Message) value);
} else {
FieldSet.writeField(field, value, output);
}
}
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
unknownFields.writeAsMessageSetTo(output);
} else {
unknownFields.writeTo(output);
}
}
private int memoizedSize = -1;
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
return size;
}
size = 0;
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
field.getNumber(), (Message) value);
} else {
size += FieldSet.computeFieldSize(field, value);
}
}
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size += unknownFields.getSerializedSize();
}
memoizedSize = size;
return size;
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Message)) {
return false;
}
final Message otherMessage = (Message) other;
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
return false;
}
return getAllFields().equals(otherMessage.getAllFields()) &&
getUnknownFields().equals(otherMessage.getUnknownFields());
}
@Override
public int hashCode() {
int hash = 41;
hash = (19 * hash) + getDescriptorForType().hashCode();
hash = (53 * hash) + getAllFields().hashCode();
hash = (29 * hash) + getUnknownFields().hashCode();
return hash;
}
// =================================================================
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType>
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType clear() {
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
clearField(entry.getKey());
}
return (BuilderType) this;
}
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
// Note: We don't attempt to verify that other's fields have valid
// types. Doing so would be a losing battle. We'd have to verify
// all sub-messages as well, and we'd have to make copies of all of
// them to insure that they don't change after verification (since
// the Message interface itself cannot enforce immutability of
// implementations).
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
// which allows people to make secure deep copies of messages.
for (final Map.Entry<FieldDescriptor, Object> entry :
other.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
for (final Object element : (List)entry.getValue()) {
addRepeatedField(field, element);
}
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
final Message existingValue = (Message)getField(field);
if (existingValue == existingValue.getDefaultInstanceForType()) {
setField(field, entry.getValue());
} else {
setField(field,
existingValue.newBuilderForType()
.mergeFrom(existingValue)
.mergeFrom((Message)entry.getValue())
.build());
}
} else {
setField(field, entry.getValue());
}
}
mergeUnknownFields(other.getUnknownFields());
return (BuilderType) this;
}
@Override
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
}
@Override
public BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final UnknownFieldSet.Builder unknownFields =
UnknownFieldSet.newBuilder(getUnknownFields());
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
this, tag)) {
// end group tag
break;
}
}
setUnknownFields(unknownFields.build());
return (BuilderType) this;
}
/**
* Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
* ExtensionRegistryLite, Message.Builder)}, but parses a single field.
* Package-private because it is used by GeneratedMessage.ExtendableMessage.
* @param tag The tag, which should have already been read.
* @return {@code true} unless the tag is an end-group tag.
*/
static boolean mergeFieldFrom(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final Message.Builder builder,
final int tag) throws IOException {
final Descriptor type = builder.getDescriptorForType();
if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
input, unknownFields, extensionRegistry, builder);
return true;
}
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final FieldDescriptor field;
Message defaultInstance = null;
if (type.isExtensionNumber(fieldNumber)) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
final ExtensionRegistry.ExtensionInfo extension =
((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, fieldNumber);
if (extension == null) {
field = null;
} else {
field = extension.descriptor;
defaultInstance = extension.defaultInstance;
if (defaultInstance == null &&
field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalStateException(
"Message-typed extension lacked default instance: " +
field.getFullName());
}
}
} else {
field = null;
}
} else {
field = type.findFieldByNumber(fieldNumber);
}
boolean unknown = false;
boolean packed = false;
if (field == null) {
unknown = true; // Unknown field.
} else if (wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
false /* isPacked */)) {
packed = false;
} else if (field.isPackable() &&
wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
true /* isPacked */)) {
packed = true;
} else {
unknown = true; // Unknown wire type.
}
if (unknown) { // Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input);
}
if (packed) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value = field.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
builder.addRepeatedField(field, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
FieldSet.readPrimitiveField(input, field.getLiteType());
builder.addRepeatedField(field, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (field.getType()) {
case GROUP: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
subBuilder.mergeFrom((Message) builder.getField(field));
}
input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
value = subBuilder.build();
break;
}
case MESSAGE: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
subBuilder.mergeFrom((Message) builder.getField(field));
}
input.readMessage(subBuilder, extensionRegistry);
value = subBuilder.build();
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input, field.getLiteType());
break;
}
if (field.isRepeated()) {
builder.addRepeatedField(field, value);
} else {
builder.setField(field, value);
}
}
return true;
}
/** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
private static void mergeMessageSetExtensionFromCodedStream(
final CodedInputStream input,
final UnknownFieldSet.Builder unknownFields,
final ExtensionRegistryLite extensionRegistry,
final Message.Builder builder) throws IOException {
final Descriptor type = builder.getDescriptorForType();
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
Message.Builder subBuilder = null;
FieldDescriptor field = null;
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
typeId = input.readUInt32();
// Zero is not a valid type ID.
if (typeId != 0) {
final ExtensionRegistry.ExtensionInfo extension;
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
extension = ((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, typeId);
} else {
extension = null;
}
if (extension != null) {
field = extension.descriptor;
subBuilder = extension.defaultInstance.newBuilderForType();
final Message originalMessage = (Message)builder.getField(field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
if (rawBytes != null) {
// We already encountered the message. Parse it now.
subBuilder.mergeFrom(
CodedInputStream.newInstance(rawBytes.newInput()));
rawBytes = null;
}
} else {
// Unknown extension number. If we already saw data, put it
// in rawBytes.
if (rawBytes != null) {
unknownFields.mergeField(typeId,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes)
.build());
rawBytes = null;
}
}
}
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
if (typeId == 0) {
// We haven't seen a type ID yet, so we have to store the raw bytes
// for now.
rawBytes = input.readBytes();
} else if (subBuilder == null) {
// We don't know how to parse this. Ignore it.
unknownFields.mergeField(typeId,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(input.readBytes())
.build());
} else {
// We already know the type, so we can parse directly from the input
// with no copying. Hooray!
input.readMessage(subBuilder, extensionRegistry);
}
} else {
// Unknown tag. Skip it.
if (!input.skipField(tag)) {
break; // end of group
}
}
}
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
if (subBuilder != null) {
builder.setField(field, subBuilder.build());
}
}
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
.mergeFrom(unknownFields)
.build());
return (BuilderType) this;
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(Message message) {
return new UninitializedMessageException(findMissingFields(message));
}
/**
* Populates {@code this.missingFields} with the full "path" of each
* missing required field in the given message.
*/
private static List<String> findMissingFields(final Message message) {
final List<String> results = new ArrayList<String>();
findMissingFields(message, "", results);
return results;
}
/** Recursive helper implementing {@link #findMissingFields(Message)}. */
private static void findMissingFields(final Message message,
final String prefix,
final List<String> results) {
for (final FieldDescriptor field :
message.getDescriptorForType().getFields()) {
if (field.isRequired() && !message.hasField(field)) {
results.add(prefix + field.getName());
}
}
for (final Map.Entry<FieldDescriptor, Object> entry :
message.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
int i = 0;
for (final Object element : (List) value) {
findMissingFields((Message) element,
subMessagePrefix(prefix, field, i++),
results);
}
} else {
if (message.hasField(field)) {
findMissingFields((Message) value,
subMessagePrefix(prefix, field, -1),
results);
}
}
}
}
}
private static String subMessagePrefix(final String prefix,
final FieldDescriptor field,
final int index) {
final StringBuilder result = new StringBuilder(prefix);
if (field.isExtension()) {
result.append('(')
.append(field.getFullName())
.append(')');
} else {
result.append(field.getName());
}
if (index != -1) {
result.append('[')
.append(index)
.append(']');
}
result.append('.');
return result.toString();
}
// ===============================================================
// The following definitions seem to be required in order to make javac
// not produce weird errors like:
//
// java/com/google/protobuf/DynamicMessage.java:203: types
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> and
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
// return types.
//
// Strangely, these lines are only needed if javac is invoked separately
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
// invoked on both simultaneously, it works. (Or maybe the important
// point is whether or not DynamicMessage.java is compiled together with
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
// bug.
@Override
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, off, len);
}
@Override
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, off, len, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final InputStream input)
throws IOException {
return super.mergeFrom(input);
}
@Override
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeFrom(input, extensionRegistry);
}
@Override
public boolean mergeDelimitedFrom(final InputStream input)
throws IOException {
return super.mergeDelimitedFrom(input);
}
@Override
public boolean mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeDelimitedFrom(input, extensionRegistry);
}
}
}

View file

@ -0,0 +1,326 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
/**
* A partial implementation of the {@link MessageLite} interface which
* implements as many methods of that interface as possible in terms of other
* methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessageLite implements MessageLite {
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
public void writeTo(final OutputStream output) throws IOException {
final int bufferSize =
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(final OutputStream output) throws IOException {
final int serialized = getSerializedSize();
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
codedOutput.writeRawVarint32(serialized);
writeTo(codedOutput);
codedOutput.flush();
}
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
implements MessageLite.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
}
// Re-defined here for return type covariance.
public abstract BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException;
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
public BuilderType mergeFrom(final byte[] data, final int off,
final int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
}
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
/**
* An InputStream implementations which reads from some other InputStream
* but is limited to a particular number of bytes. Used by
* mergeDelimitedFrom(). This is intentionally package-private so that
* UnknownFieldSet can share it.
*/
static final class LimitedInputStream extends FilterInputStream {
private int limit;
LimitedInputStream(InputStream in, int limit) {
super(in);
this.limit = limit;
}
@Override
public int available() throws IOException {
return Math.min(super.available(), limit);
}
@Override
public int read() throws IOException {
if (limit <= 0) {
return -1;
}
final int result = super.read();
if (result >= 0) {
--limit;
}
return result;
}
@Override
public int read(final byte[] b, final int off, int len)
throws IOException {
if (limit <= 0) {
return -1;
}
len = Math.min(len, limit);
final int result = super.read(b, off, len);
if (result >= 0) {
limit -= result;
}
return result;
}
@Override
public long skip(final long n) throws IOException {
final long result = super.skip(Math.min(n, limit));
if (result >= 0) {
limit -= result;
}
return result;
}
}
public boolean mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
}
final int size = CodedInputStream.readRawVarint32(firstByte, input);
final InputStream limitedInput = new LimitedInputStream(input, size);
mergeFrom(limitedInput, extensionRegistry);
return true;
}
public boolean mergeDelimitedFrom(final InputStream input)
throws IOException {
return mergeDelimitedFrom(input,
ExtensionRegistryLite.getEmptyRegistry());
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(MessageLite message) {
return new UninitializedMessageException(message);
}
/**
* Adds the {@code values} to the {@code list}. This is a helper method
* used by generated code. Users should ignore it.
*
* @throws NullPointerException if any of the elements of {@code values} is
* null.
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
for (final T value : values) {
if (value == null) {
throw new NullPointerException();
}
}
if (values instanceof Collection) {
final
Collection<T> collection = (Collection<T>) values;
list.addAll(collection);
} else {
for (final T value : values) {
list.add(value);
}
}
}
}
}

View file

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
* is the blocking equivalent to {@link RpcChannel}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingRpcChannel {
/**
* Call the given method of the remote service and blocks until it returns.
* {@code callBlockingMethod()} is the blocking equivalent to
* {@link RpcChannel#callMethod}.
*/
Message callBlockingMethod(
Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
Message responsePrototype) throws ServiceException;
}

View file

@ -0,0 +1,64 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Blocking equivalent to {@link Service}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingService {
/**
* Equivalent to {@link Service#getDescriptorForType}.
*/
Descriptors.ServiceDescriptor getDescriptorForType();
/**
* Equivalent to {@link Service#callMethod}, except that
* {@code callBlockingMethod()} returns the result of the RPC or throws a
* {@link ServiceException} if there is a failure, rather than passing the
* information to a callback.
*/
Message callBlockingMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request) throws ServiceException;
/**
* Equivalent to {@link Service#getRequestPrototype}.
*/
Message getRequestPrototype(Descriptors.MethodDescriptor method);
/**
* Equivalent to {@link Service#getResponsePrototype}.
*/
Message getResponsePrototype(Descriptors.MethodDescriptor method);
}

View file

@ -0,0 +1,391 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.List;
/**
* Immutable array of bytes.
*
* @author crazybob@google.com Bob Lee
* @author kenton@google.com Kenton Varda
*/
public final class ByteString {
private final byte[] bytes;
private ByteString(final byte[] bytes) {
this.bytes = bytes;
}
/**
* Gets the byte at the given index.
*
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
public byte byteAt(final int index) {
return bytes[index];
}
/**
* Gets the number of bytes.
*/
public int size() {
return bytes.length;
}
/**
* Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
*/
public boolean isEmpty() {
return bytes.length == 0;
}
// =================================================================
// byte[] -> ByteString
/**
* Empty ByteString.
*/
public static final ByteString EMPTY = new ByteString(new byte[0]);
/**
* Copies the given bytes into a {@code ByteString}.
*/
public static ByteString copyFrom(final byte[] bytes, final int offset,
final int size) {
final byte[] copy = new byte[size];
System.arraycopy(bytes, offset, copy, 0, size);
return new ByteString(copy);
}
/**
* Copies the given bytes into a {@code ByteString}.
*/
public static ByteString copyFrom(final byte[] bytes) {
return copyFrom(bytes, 0, bytes.length);
}
/**
* Copies {@code size} bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
*/
public static ByteString copyFrom(final ByteBuffer bytes, final int size) {
final byte[] copy = new byte[size];
bytes.get(copy);
return new ByteString(copy);
}
/**
* Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
*/
public static ByteString copyFrom(final ByteBuffer bytes) {
return copyFrom(bytes, bytes.remaining());
}
/**
* Encodes {@code text} into a sequence of bytes using the named charset
* and returns the result as a {@code ByteString}.
*/
public static ByteString copyFrom(final String text, final String charsetName)
throws UnsupportedEncodingException {
return new ByteString(text.getBytes(charsetName));
}
/**
* Encodes {@code text} into a sequence of UTF-8 bytes and returns the
* result as a {@code ByteString}.
*/
public static ByteString copyFromUtf8(final String text) {
try {
return new ByteString(text.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
/**
* Concatenates all byte strings in the list and returns the result.
*
* <p>The returned {@code ByteString} is not necessarily a unique object.
* If the list is empty, the returned object is the singleton empty
* {@code ByteString}. If the list has only one element, that
* {@code ByteString} will be returned without copying.
*/
public static ByteString copyFrom(List<ByteString> list) {
if (list.size() == 0) {
return EMPTY;
} else if (list.size() == 1) {
return list.get(0);
}
int size = 0;
for (ByteString str : list) {
size += str.size();
}
byte[] bytes = new byte[size];
int pos = 0;
for (ByteString str : list) {
System.arraycopy(str.bytes, 0, bytes, pos, str.size());
pos += str.size();
}
return new ByteString(bytes);
}
// =================================================================
// ByteString -> byte[]
/**
* Copies bytes into a buffer at the given offset.
*
* @param target buffer to copy into
* @param offset in the target buffer
*/
public void copyTo(final byte[] target, final int offset) {
System.arraycopy(bytes, 0, target, offset, bytes.length);
}
/**
* Copies bytes into a buffer.
*
* @param target buffer to copy into
* @param sourceOffset offset within these bytes
* @param targetOffset offset within the target buffer
* @param size number of bytes to copy
*/
public void copyTo(final byte[] target, final int sourceOffset,
final int targetOffset,
final int size) {
System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
}
/**
* Copies bytes to a {@code byte[]}.
*/
public byte[] toByteArray() {
final int size = bytes.length;
final byte[] copy = new byte[size];
System.arraycopy(bytes, 0, copy, 0, size);
return copy;
}
/**
* Constructs a new read-only {@code java.nio.ByteBuffer} with the
* same backing byte array.
*/
public ByteBuffer asReadOnlyByteBuffer() {
final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
return byteBuffer.asReadOnlyBuffer();
}
/**
* Constructs a new {@code String} by decoding the bytes using the
* specified charset.
*/
public String toString(final String charsetName)
throws UnsupportedEncodingException {
return new String(bytes, charsetName);
}
/**
* Constructs a new {@code String} by decoding the bytes as UTF-8.
*/
public String toStringUtf8() {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
// =================================================================
// equals() and hashCode()
@Override
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ByteString)) {
return false;
}
final ByteString other = (ByteString) o;
final int size = bytes.length;
if (size != other.bytes.length) {
return false;
}
final byte[] thisBytes = bytes;
final byte[] otherBytes = other.bytes;
for (int i = 0; i < size; i++) {
if (thisBytes[i] != otherBytes[i]) {
return false;
}
}
return true;
}
private volatile int hash = 0;
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
final byte[] thisBytes = bytes;
final int size = bytes.length;
h = size;
for (int i = 0; i < size; i++) {
h = h * 31 + thisBytes[i];
}
if (h == 0) {
h = 1;
}
hash = h;
}
return h;
}
// =================================================================
// Input stream
/**
* Creates an {@code InputStream} which can be used to read the bytes.
*/
public InputStream newInput() {
return new ByteArrayInputStream(bytes);
}
/**
* Creates a {@link CodedInputStream} which can be used to read the bytes.
* Using this is more efficient than creating a {@link CodedInputStream}
* wrapping the result of {@link #newInput()}.
*/
public CodedInputStream newCodedInput() {
// We trust CodedInputStream not to modify the bytes, or to give anyone
// else access to them.
return CodedInputStream.newInstance(bytes);
}
// =================================================================
// Output stream
/**
* Creates a new {@link Output} with the given initial capacity.
*/
public static Output newOutput(final int initialCapacity) {
return new Output(new ByteArrayOutputStream(initialCapacity));
}
/**
* Creates a new {@link Output}.
*/
public static Output newOutput() {
return newOutput(32);
}
/**
* Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
* create the {@code ByteString} instance.
*/
public static final class Output extends FilterOutputStream {
private final ByteArrayOutputStream bout;
/**
* Constructs a new output with the given initial capacity.
*/
private Output(final ByteArrayOutputStream bout) {
super(bout);
this.bout = bout;
}
/**
* Creates a {@code ByteString} instance from this {@code Output}.
*/
public ByteString toByteString() {
final byte[] byteArray = bout.toByteArray();
return new ByteString(byteArray);
}
}
/**
* Constructs a new ByteString builder, which allows you to efficiently
* construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
* Using this is much more efficient than calling {@code newOutput()} and
* wrapping that in a {@code CodedOutputStream}.
*
* <p>This is package-private because it's a somewhat confusing interface.
* Users can call {@link Message#toByteString()} instead of calling this
* directly.
*
* @param size The target byte size of the {@code ByteString}. You must
* write exactly this many bytes before building the result.
*/
static CodedBuilder newCodedBuilder(final int size) {
return new CodedBuilder(size);
}
/** See {@link ByteString#newCodedBuilder(int)}. */
static final class CodedBuilder {
private final CodedOutputStream output;
private final byte[] buffer;
private CodedBuilder(final int size) {
buffer = new byte[size];
output = CodedOutputStream.newInstance(buffer);
}
public ByteString build() {
output.checkNoSpaceLeft();
// We can be confident that the CodedOutputStream will not modify the
// underlying bytes anymore because it already wrote all of them. So,
// no need to make a copy.
return new ByteString(buffer);
}
public CodedOutputStream getCodedOutput() {
return output;
}
}
}

View file

@ -0,0 +1,865 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Reads and decodes protocol message fields.
*
* This class contains two kinds of methods: methods that read specific
* protocol message constructs and field types (e.g. {@link #readTag()} and
* {@link #readInt32()}) and methods that read low-level values (e.g.
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
* encoded protocol messages, you should use the former methods, but if you are
* reading some other format of your own design, use the latter.
*
* @author kenton@google.com Kenton Varda
*/
public final class CodedInputStream {
/**
* Create a new CodedInputStream wrapping the given InputStream.
*/
public static CodedInputStream newInstance(final InputStream input) {
return new CodedInputStream(input);
}
/**
* Create a new CodedInputStream wrapping the given byte array.
*/
public static CodedInputStream newInstance(final byte[] buf) {
return newInstance(buf, 0, buf.length);
}
/**
* Create a new CodedInputStream wrapping the given byte array slice.
*/
public static CodedInputStream newInstance(final byte[] buf, final int off,
final int len) {
return new CodedInputStream(buf, off, len);
}
// -----------------------------------------------------------------
/**
* Attempt to read a field tag, returning zero if we have reached EOF.
* Protocol message parsers use this to read tags, since a protocol message
* may legally end wherever a tag occurs, and zero is not a valid tag number.
*/
public int readTag() throws IOException {
if (isAtEnd()) {
lastTag = 0;
return 0;
}
lastTag = readRawVarint32();
if (WireFormat.getTagFieldNumber(lastTag) == 0) {
// If we actually read zero (or any tag number corresponding to field
// number zero), that's not a valid tag.
throw InvalidProtocolBufferException.invalidTag();
}
return lastTag;
}
/**
* Verifies that the last call to readTag() returned the given tag value.
* This is used to verify that a nested group ended with the correct
* end tag.
*
* @throws InvalidProtocolBufferException {@code value} does not match the
* last tag.
*/
public void checkLastTagWas(final int value)
throws InvalidProtocolBufferException {
if (lastTag != value) {
throw InvalidProtocolBufferException.invalidEndTag();
}
}
/**
* Reads and discards a single field, given its tag value.
*
* @return {@code false} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code true}.
*/
public boolean skipField(final int tag) throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
readInt32();
return true;
case WireFormat.WIRETYPE_FIXED64:
readRawLittleEndian64();
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
return true;
case WireFormat.WIRETYPE_START_GROUP:
skipMessage();
checkLastTagWas(
WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
WireFormat.WIRETYPE_END_GROUP));
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
readRawLittleEndian32();
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Reads and discards an entire message. This will read either until EOF
* or until an endgroup tag, whichever comes first.
*/
public void skipMessage() throws IOException {
while (true) {
final int tag = readTag();
if (tag == 0 || !skipField(tag)) {
return;
}
}
}
// -----------------------------------------------------------------
/** Read a {@code double} field value from the stream. */
public double readDouble() throws IOException {
return Double.longBitsToDouble(readRawLittleEndian64());
}
/** Read a {@code float} field value from the stream. */
public float readFloat() throws IOException {
return Float.intBitsToFloat(readRawLittleEndian32());
}
/** Read a {@code uint64} field value from the stream. */
public long readUInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int64} field value from the stream. */
public long readInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int32} field value from the stream. */
public int readInt32() throws IOException {
return readRawVarint32();
}
/** Read a {@code fixed64} field value from the stream. */
public long readFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read a {@code fixed32} field value from the stream. */
public int readFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read a {@code bool} field value from the stream. */
public boolean readBool() throws IOException {
return readRawVarint32() != 0;
}
/** Read a {@code string} field value from the stream. */
public String readString() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return new String(readRawBytes(size), "UTF-8");
}
}
/** Read a {@code group} field value from the stream. */
public void readGroup(final int fieldNumber,
final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
++recursionDepth;
builder.mergeFrom(this, extensionRegistry);
checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
--recursionDepth;
}
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link UnknownFieldSet}.
*
* @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
* you can just call {@link #readGroup}.
*/
@Deprecated
public void readUnknownGroup(final int fieldNumber,
final MessageLite.Builder builder)
throws IOException {
// We know that UnknownFieldSet will ignore any ExtensionRegistry so it
// is safe to pass null here. (We can't call
// ExtensionRegistry.getEmptyRegistry() because that would make this
// class depend on ExtensionRegistry, which is not part of the lite
// library.)
readGroup(fieldNumber, builder, null);
}
/** Read an embedded message field value from the stream. */
public void readMessage(final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final int length = readRawVarint32();
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
final int oldLimit = pushLimit(length);
++recursionDepth;
builder.mergeFrom(this, extensionRegistry);
checkLastTagWas(0);
--recursionDepth;
popLimit(oldLimit);
}
/** Read a {@code bytes} field value from the stream. */
public ByteString readBytes() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return ByteString.copyFrom(readRawBytes(size));
}
}
/** Read a {@code uint32} field value from the stream. */
public int readUInt32() throws IOException {
return readRawVarint32();
}
/**
* Read an enum field value from the stream. Caller is responsible
* for converting the numeric value to an actual enum.
*/
public int readEnum() throws IOException {
return readRawVarint32();
}
/** Read an {@code sfixed32} field value from the stream. */
public int readSFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read an {@code sfixed64} field value from the stream. */
public long readSFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read an {@code sint32} field value from the stream. */
public int readSInt32() throws IOException {
return decodeZigZag32(readRawVarint32());
}
/** Read an {@code sint64} field value from the stream. */
public long readSInt64() throws IOException {
return decodeZigZag64(readRawVarint64());
}
// =================================================================
/**
* Read a raw Varint from the stream. If larger than 32 bits, discard the
* upper bits.
*/
public int readRawVarint32() throws IOException {
byte tmp = readRawByte();
if (tmp >= 0) {
return tmp;
}
int result = tmp & 0x7f;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
result |= (tmp = readRawByte()) << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if (readRawByte() >= 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
}
}
}
return result;
}
/**
* Reads a varint from the input one byte at a time, so that it does not
* read any bytes after the end of the varint. If you simply wrapped the
* stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
* then you would probably end up reading past the end of the varint since
* CodedInputStream buffers its input.
*/
static int readRawVarint32(final InputStream input) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
return readRawVarint32(firstByte, input);
}
/**
* Like {@link #readRawVarint32(InputStream)}, but expects that the caller
* has already read one byte. This allows the caller to determine if EOF
* has been reached before attempting to read.
*/
static int readRawVarint32(final int firstByte,
final InputStream input) throws IOException {
if ((firstByte & 0x80) == 0) {
return firstByte;
}
int result = firstByte & 0x7f;
int offset = 7;
for (; offset < 32; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
result |= (b & 0x7f) << offset;
if ((b & 0x80) == 0) {
return result;
}
}
// Keep reading up to 64 bits.
for (; offset < 64; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
if ((b & 0x80) == 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a raw Varint from the stream. */
public long readRawVarint64() throws IOException {
int shift = 0;
long result = 0;
while (shift < 64) {
final byte b = readRawByte();
result |= (long)(b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a 32-bit little-endian integer from the stream. */
public int readRawLittleEndian32() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
return (((int)b1 & 0xff) ) |
(((int)b2 & 0xff) << 8) |
(((int)b3 & 0xff) << 16) |
(((int)b4 & 0xff) << 24);
}
/** Read a 64-bit little-endian integer from the stream. */
public long readRawLittleEndian64() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
final byte b5 = readRawByte();
final byte b6 = readRawByte();
final byte b7 = readRawByte();
final byte b8 = readRawByte();
return (((long)b1 & 0xff) ) |
(((long)b2 & 0xff) << 8) |
(((long)b3 & 0xff) << 16) |
(((long)b4 & 0xff) << 24) |
(((long)b5 & 0xff) << 32) |
(((long)b6 & 0xff) << 40) |
(((long)b7 & 0xff) << 48) |
(((long)b8 & 0xff) << 56);
}
/**
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 32-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 32-bit integer.
*/
public static int decodeZigZag32(final int n) {
return (n >>> 1) ^ -(n & 1);
}
/**
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 64-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 64-bit integer.
*/
public static long decodeZigZag64(final long n) {
return (n >>> 1) ^ -(n & 1);
}
// -----------------------------------------------------------------
private final byte[] buffer;
private int bufferSize;
private int bufferSizeAfterLimit;
private int bufferPos;
private final InputStream input;
private int lastTag;
/**
* The total number of bytes read before the current buffer. The total
* bytes read up to the current position can be computed as
* {@code totalBytesRetired + bufferPos}. This value may be negative if
* reading started in the middle of the current buffer (e.g. if the
* constructor that takes a byte array and an offset was used).
*/
private int totalBytesRetired;
/** The absolute position of the end of the current message. */
private int currentLimit = Integer.MAX_VALUE;
/** See setRecursionLimit() */
private int recursionDepth;
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
/** See setSizeLimit() */
private int sizeLimit = DEFAULT_SIZE_LIMIT;
private static final int DEFAULT_RECURSION_LIMIT = 64;
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
private static final int BUFFER_SIZE = 4096;
private CodedInputStream(final byte[] buffer, final int off, final int len) {
this.buffer = buffer;
bufferSize = off + len;
bufferPos = off;
totalBytesRetired = -off;
input = null;
}
private CodedInputStream(final InputStream input) {
buffer = new byte[BUFFER_SIZE];
bufferSize = 0;
bufferPos = 0;
totalBytesRetired = 0;
this.input = input;
}
/**
* Set the maximum message recursion depth. In order to prevent malicious
* messages from causing stack overflows, {@code CodedInputStream} limits
* how deeply messages may be nested. The default limit is 64.
*
* @return the old limit.
*/
public int setRecursionLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Recursion limit cannot be negative: " + limit);
}
final int oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}
/**
* Set the maximum message size. In order to prevent malicious
* messages from exhausting memory or causing integer overflows,
* {@code CodedInputStream} limits how large a message may be.
* The default limit is 64MB. You should set this limit as small
* as you can without harming your app's functionality. Note that
* size limits only apply when reading from an {@code InputStream}, not
* when constructed around a raw byte array (nor with
* {@link ByteString#newCodedInput}).
* <p>
* If you want to read several messages from a single CodedInputStream, you
* could call {@link #resetSizeCounter()} after each one to avoid hitting the
* size limit.
*
* @return the old limit.
*/
public int setSizeLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Size limit cannot be negative: " + limit);
}
final int oldLimit = sizeLimit;
sizeLimit = limit;
return oldLimit;
}
/**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
*/
public void resetSizeCounter() {
totalBytesRetired = -bufferPos;
}
/**
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
* is called when descending into a length-delimited embedded message.
*
* <p>Note that {@code pushLimit()} does NOT affect how many bytes the
* {@code CodedInputStream} reads from an underlying {@code InputStream} when
* refreshing its buffer. If you need to prevent reading past a certain
* point in the underlying {@code InputStream} (e.g. because you expect it to
* contain more data after the end of the message which you need to handle
* differently) then you must place a wrapper around you {@code InputStream}
* which limits the amount of data that can be read from it.
*
* @return the old limit.
*/
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
if (byteLimit < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + bufferPos;
final int oldLimit = currentLimit;
if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();
}
currentLimit = byteLimit;
recomputeBufferSizeAfterLimit();
return oldLimit;
}
private void recomputeBufferSizeAfterLimit() {
bufferSize += bufferSizeAfterLimit;
final int bufferEnd = totalBytesRetired + bufferSize;
if (bufferEnd > currentLimit) {
// Limit is in current buffer.
bufferSizeAfterLimit = bufferEnd - currentLimit;
bufferSize -= bufferSizeAfterLimit;
} else {
bufferSizeAfterLimit = 0;
}
}
/**
* Discards the current limit, returning to the previous limit.
*
* @param oldLimit The old limit, as returned by {@code pushLimit}.
*/
public void popLimit(final int oldLimit) {
currentLimit = oldLimit;
recomputeBufferSizeAfterLimit();
}
/**
* Returns the number of bytes to be read before the current limit.
* If no limit is set, returns -1.
*/
public int getBytesUntilLimit() {
if (currentLimit == Integer.MAX_VALUE) {
return -1;
}
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
return currentLimit - currentAbsolutePosition;
}
/**
* Returns true if the stream has reached the end of the input. This is the
* case if either the end of the underlying input source has been reached or
* if the stream has reached a limit created using {@link #pushLimit(int)}.
*/
public boolean isAtEnd() throws IOException {
return bufferPos == bufferSize && !refillBuffer(false);
}
/**
* The total bytes read up to the current position. Calling
* {@link #resetSizeCounter()} resets this value to zero.
*/
public int getTotalBytesRead() {
return totalBytesRetired + bufferPos;
}
/**
* Called with {@code this.buffer} is empty to read more bytes from the
* input. If {@code mustSucceed} is true, refillBuffer() gurantees that
* either there will be at least one byte in the buffer when it returns
* or it will throw an exception. If {@code mustSucceed} is false,
* refillBuffer() returns false if no more bytes were available.
*/
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
if (bufferPos < bufferSize) {
throw new IllegalStateException(
"refillBuffer() called when buffer wasn't empty.");
}
if (totalBytesRetired + bufferSize == currentLimit) {
// Oops, we hit a limit.
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
}
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = (input == null) ? -1 : input.read(buffer);
if (bufferSize == 0 || bufferSize < -1) {
throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: " + bufferSize +
"\nThe InputStream implementation is buggy.");
}
if (bufferSize == -1) {
bufferSize = 0;
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
} else {
recomputeBufferSizeAfterLimit();
final int totalBytesRead =
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
}
return true;
}
}
/**
* Read one byte from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte readRawByte() throws IOException {
if (bufferPos == bufferSize) {
refillBuffer(true);
}
return buffer[bufferPos++];
}
/**
* Read a fixed size of bytes from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte[] readRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
final byte[] bytes = new byte[size];
System.arraycopy(buffer, bufferPos, bytes, 0, size);
bufferPos += size;
return bytes;
} else if (size < BUFFER_SIZE) {
// Reading more bytes than are in the buffer, but not an excessive number
// of bytes. We can safely allocate the resulting array ahead of time.
// First copy what we have.
final byte[] bytes = new byte[size];
int pos = bufferSize - bufferPos;
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
bufferPos = bufferSize;
// We want to use refillBuffer() and then copy from the buffer into our
// byte array rather than reading directly into our byte array because
// the input may be unbuffered.
refillBuffer(true);
while (size - pos > bufferSize) {
System.arraycopy(buffer, 0, bytes, pos, bufferSize);
pos += bufferSize;
bufferPos = bufferSize;
refillBuffer(true);
}
System.arraycopy(buffer, 0, bytes, pos, size - pos);
bufferPos = size - pos;
return bytes;
} else {
// The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in
// order to trick the app into allocating a lot of memory. We avoid this
// by allocating and reading only a small chunk at a time, so that the
// malicious message must actually *be* extremely large to cause
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
// Remember the buffer markers since we'll have to copy the bytes out of
// it later.
final int originalBufferPos = bufferPos;
final int originalBufferSize = bufferSize;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = 0;
// Read all the rest of the bytes we need.
int sizeLeft = size - (originalBufferSize - originalBufferPos);
final List<byte[]> chunks = new ArrayList<byte[]>();
while (sizeLeft > 0) {
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
int pos = 0;
while (pos < chunk.length) {
final int n = (input == null) ? -1 :
input.read(chunk, pos, chunk.length - pos);
if (n == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
totalBytesRetired += n;
pos += n;
}
sizeLeft -= chunk.length;
chunks.add(chunk);
}
// OK, got everything. Now concatenate it all into one buffer.
final byte[] bytes = new byte[size];
// Start by copying the leftover bytes from this.buffer.
int pos = originalBufferSize - originalBufferPos;
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
// And now all the chunks.
for (final byte[] chunk : chunks) {
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
pos += chunk.length;
}
// Done.
return bytes;
}
}
/**
* Reads and discards {@code size} bytes.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public void skipRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
bufferPos += size;
} else {
// Skipping more bytes than are in the buffer. First skip what we have.
int pos = bufferSize - bufferPos;
totalBytesRetired += pos;
bufferPos = 0;
bufferSize = 0;
// Then skip directly from the InputStream for the rest.
while (pos < size) {
final int n = (input == null) ? -1 : (int) input.skip(size - pos);
if (n <= 0) {
throw InvalidProtocolBufferException.truncatedMessage();
}
pos += n;
totalBytesRetired += n;
}
}
}
}

View file

@ -0,0 +1,814 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
/**
* Reads and decodes protocol message fields.
*
* This class contains two kinds of methods: methods that read specific
* protocol message constructs and field types (e.g. {@link #readTag()} and
* {@link #readInt32()}) and methods that read low-level values (e.g.
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
* encoded protocol messages, you should use the former methods, but if you are
* reading some other format of your own design, use the latter.
*
* @author kenton@google.com Kenton Varda
*/
public final class CodedInputStreamRAF {
/**
* Create a new CodedInputStream wrapping the given InputStream.
*/
public static CodedInputStreamRAF newInstance(RandomAccessFile raf) {
return new CodedInputStreamRAF(raf, BUFFER_SIZE_DEF);
}
public static CodedInputStreamRAF newInstance(RandomAccessFile raf, int bufferSize) {
return new CodedInputStreamRAF(raf, bufferSize);
}
// -----------------------------------------------------------------
/**
* Attempt to read a field tag, returning zero if we have reached EOF.
* Protocol message parsers use this to read tags, since a protocol message
* may legally end wherever a tag occurs, and zero is not a valid tag number.
*/
public int readTag() throws IOException {
if (isAtEnd()) {
lastTag = 0;
return 0;
}
lastTag = readRawVarint32();
if (WireFormat.getTagFieldNumber(lastTag) == 0) {
// If we actually read zero (or any tag number corresponding to field
// number zero), that's not a valid tag.
throw InvalidProtocolBufferException.invalidTag();
}
return lastTag;
}
/**
* Verifies that the last call to readTag() returned the given tag value.
* This is used to verify that a nested group ended with the correct
* end tag.
*
* @throws InvalidProtocolBufferException {@code value} does not match the
* last tag.
*/
public void checkLastTagWas(final int value)
throws InvalidProtocolBufferException {
if (lastTag != value) {
throw InvalidProtocolBufferException.invalidEndTag();
}
}
/**
* Reads and discards a single field, given its tag value.
*
* @return {@code false} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code true}.
*/
public boolean skipField(final int tag) throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
readInt32();
return true;
case WireFormat.WIRETYPE_FIXED64:
readRawLittleEndian64();
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
return true;
case WireFormat.WIRETYPE_START_GROUP:
skipMessage();
checkLastTagWas(
WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
WireFormat.WIRETYPE_END_GROUP));
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
readRawLittleEndian32();
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Reads and discards an entire message. This will read either until EOF
* or until an endgroup tag, whichever comes first.
*/
public void skipMessage() throws IOException {
while (true) {
final int tag = readTag();
if (tag == 0 || !skipField(tag)) {
return;
}
}
}
// -----------------------------------------------------------------
/** Read a {@code double} field value from the stream. */
public double readDouble() throws IOException {
return Double.longBitsToDouble(readRawLittleEndian64());
}
/** Read a {@code float} field value from the stream. */
public float readFloat() throws IOException {
return Float.intBitsToFloat(readRawLittleEndian32());
}
/** Read a {@code uint64} field value from the stream. */
public long readUInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int64} field value from the stream. */
public long readInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int32} field value from the stream. */
public int readInt32() throws IOException {
return readRawVarint32();
}
/** Read a {@code fixed64} field value from the stream. */
public long readFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read a {@code fixed32} field value from the stream. */
public int readFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read a {@code bool} field value from the stream. */
public boolean readBool() throws IOException {
return readRawVarint32() != 0;
}
/** Read a {@code string} field value from the stream. */
public String readString() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return new String(readRawBytes(size), "UTF-8");
}
}
/** Read a {@code bytes} field value from the stream. */
public ByteString readBytes() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return ByteString.copyFrom(readRawBytes(size));
}
}
/** Read a {@code uint32} field value from the stream. */
public int readUInt32() throws IOException {
return readRawVarint32();
}
/**
* Read an enum field value from the stream. Caller is responsible
* for converting the numeric value to an actual enum.
*/
public int readEnum() throws IOException {
return readRawVarint32();
}
/** Read an {@code sfixed32} field value from the stream. */
public int readSFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read an {@code sfixed64} field value from the stream. */
public long readSFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read an {@code sint32} field value from the stream. */
public int readSInt32() throws IOException {
return decodeZigZag32(readRawVarint32());
}
/** Read an {@code sint64} field value from the stream. */
public long readSInt64() throws IOException {
return decodeZigZag64(readRawVarint64());
}
// =================================================================
/**
* Read a raw Varint from the stream. If larger than 32 bits, discard the
* upper bits.
*/
public int readRawVarint32() throws IOException {
byte tmp = readRawByte();
if (tmp >= 0) {
return tmp;
}
int result = tmp & 0x7f;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
result |= (tmp = readRawByte()) << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if (readRawByte() >= 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
}
}
}
return result;
}
/**
* Reads a varint from the input one byte at a time, so that it does not
* read any bytes after the end of the varint. If you simply wrapped the
* stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
* then you would probably end up reading past the end of the varint since
* CodedInputStream buffers its input.
*/
static int readRawVarint32(final InputStream input) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
return readRawVarint32(firstByte, input);
}
/**
* Like {@link #readRawVarint32(InputStream)}, but expects that the caller
* has already read one byte. This allows the caller to determine if EOF
* has been reached before attempting to read.
*/
static int readRawVarint32(final int firstByte,
final InputStream input) throws IOException {
if ((firstByte & 0x80) == 0) {
return firstByte;
}
int result = firstByte & 0x7f;
int offset = 7;
for (; offset < 32; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
result |= (b & 0x7f) << offset;
if ((b & 0x80) == 0) {
return result;
}
}
// Keep reading up to 64 bits.
for (; offset < 64; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
if ((b & 0x80) == 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a raw Varint from the stream. */
public long readRawVarint64() throws IOException {
int shift = 0;
long result = 0;
while (shift < 64) {
final byte b = readRawByte();
result |= (long)(b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a 32-bit little-endian integer from the stream. */
public int readRawLittleEndian32() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
return (((int)b1 & 0xff) ) |
(((int)b2 & 0xff) << 8) |
(((int)b3 & 0xff) << 16) |
(((int)b4 & 0xff) << 24);
}
/** Read a 64-bit little-endian integer from the stream. */
public long readRawLittleEndian64() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
final byte b5 = readRawByte();
final byte b6 = readRawByte();
final byte b7 = readRawByte();
final byte b8 = readRawByte();
return (((long)b1 & 0xff) ) |
(((long)b2 & 0xff) << 8) |
(((long)b3 & 0xff) << 16) |
(((long)b4 & 0xff) << 24) |
(((long)b5 & 0xff) << 32) |
(((long)b6 & 0xff) << 40) |
(((long)b7 & 0xff) << 48) |
(((long)b8 & 0xff) << 56);
}
/**
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 32-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 32-bit integer.
*/
public static int decodeZigZag32(final int n) {
return (n >>> 1) ^ -(n & 1);
}
/**
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 64-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 64-bit integer.
*/
public static long decodeZigZag64(final long n) {
return (n >>> 1) ^ -(n & 1);
}
// -----------------------------------------------------------------
private final byte[] buffer;
private int bufferSize;
private int bufferSizeAfterLimit;
private int bufferPos;
private final RandomAccessFile raf;
private int lastTag;
/**
* The total number of bytes read before the current buffer. The total
* bytes read up to the current position can be computed as
* {@code totalBytesRetired + bufferPos}. This value may be negative if
* reading started in the middle of the current buffer (e.g. if the
* constructor that takes a byte array and an offset was used).
*/
private int totalBytesRetired;
/** The absolute position of the end of the current message. */
private int currentLimit = Integer.MAX_VALUE;
/** See setRecursionLimit() */
private int recursionDepth;
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
/** See setSizeLimit() */
private int sizeLimit = DEFAULT_SIZE_LIMIT;
private static final int DEFAULT_RECURSION_LIMIT = 64;
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
private static final int BUFFER_SIZE_DEF = 4096;
private int BUFFER_SIZE = BUFFER_SIZE_DEF;
private CodedInputStreamRAF(final RandomAccessFile raf, int bufferSize) {
BUFFER_SIZE = bufferSize;
buffer = new byte[BUFFER_SIZE];
bufferSize = 0;
bufferPos = 0;
totalBytesRetired = 0;
this.raf = raf;
}
/**
* Set the maximum message recursion depth. In order to prevent malicious
* messages from causing stack overflows, {@code CodedInputStream} limits
* how deeply messages may be nested. The default limit is 64.
*
* @return the old limit.
*/
public int setRecursionLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Recursion limit cannot be negative: " + limit);
}
final int oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}
/**
* Set the maximum message size. In order to prevent malicious
* messages from exhausting memory or causing integer overflows,
* {@code CodedInputStream} limits how large a message may be.
* The default limit is 64MB. You should set this limit as small
* as you can without harming your app's functionality. Note that
* size limits only apply when reading from an {@code InputStream}, not
* when constructed around a raw byte array (nor with
* {@link ByteString#newCodedInput}).
* <p>
* If you want to read several messages from a single CodedInputStream, you
* could call {@link #resetSizeCounter()} after each one to avoid hitting the
* size limit.
*
* @return the old limit.
*/
public int setSizeLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Size limit cannot be negative: " + limit);
}
final int oldLimit = sizeLimit;
sizeLimit = limit;
return oldLimit;
}
/**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
*/
public void resetSizeCounter() {
totalBytesRetired = -bufferPos;
}
/**
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
* is called when descending into a length-delimited embedded message.
*
* <p>Note that {@code pushLimit()} does NOT affect how many bytes the
* {@code CodedInputStream} reads from an underlying {@code InputStream} when
* refreshing its buffer. If you need to prevent reading past a certain
* point in the underlying {@code InputStream} (e.g. because you expect it to
* contain more data after the end of the message which you need to handle
* differently) then you must place a wrapper around you {@code InputStream}
* which limits the amount of data that can be read from it.
*
* @return the old limit.
*/
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
if (byteLimit < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + bufferPos;
final int oldLimit = currentLimit;
if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();
}
currentLimit = byteLimit;
recomputeBufferSizeAfterLimit();
return oldLimit;
}
private void recomputeBufferSizeAfterLimit() {
bufferSize += bufferSizeAfterLimit;
final int bufferEnd = totalBytesRetired + bufferSize;
if (bufferEnd > currentLimit) {
// Limit is in current buffer.
bufferSizeAfterLimit = bufferEnd - currentLimit;
bufferSize -= bufferSizeAfterLimit;
} else {
bufferSizeAfterLimit = 0;
}
}
/**
* Discards the current limit, returning to the previous limit.
*
* @param oldLimit The old limit, as returned by {@code pushLimit}.
*/
public void popLimit(final int oldLimit) {
currentLimit = oldLimit;
recomputeBufferSizeAfterLimit();
}
/**
* Returns the number of bytes to be read before the current limit.
* If no limit is set, returns -1.
*/
public int getBytesUntilLimit() {
if (currentLimit == Integer.MAX_VALUE) {
return -1;
}
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
return currentLimit - currentAbsolutePosition;
}
/**
* Returns true if the stream has reached the end of the input. This is the
* case if either the end of the underlying input source has been reached or
* if the stream has reached a limit created using {@link #pushLimit(int)}.
*/
public boolean isAtEnd() throws IOException {
return bufferPos == bufferSize && !refillBuffer(false);
}
/**
* The total bytes read up to the current position. Calling
* {@link #resetSizeCounter()} resets this value to zero.
*/
public int getTotalBytesRead() {
return totalBytesRetired + bufferPos;
}
/**
* Called with {@code this.buffer} is empty to read more bytes from the
* input. If {@code mustSucceed} is true, refillBuffer() gurantees that
* either there will be at least one byte in the buffer when it returns
* or it will throw an exception. If {@code mustSucceed} is false,
* refillBuffer() returns false if no more bytes were available.
*/
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
if (bufferPos < bufferSize) {
throw new IllegalStateException(
"refillBuffer() called when buffer wasn't empty.");
}
if (totalBytesRetired + bufferSize == currentLimit) {
// Oops, we hit a limit.
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
}
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = raf.read(buffer);
if (bufferSize == 0 || bufferSize < -1) {
throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: " + bufferSize +
"\nThe InputStream implementation is buggy.");
}
if (bufferSize == -1) {
bufferSize = 0;
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
} else {
recomputeBufferSizeAfterLimit();
final int totalBytesRead =
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
}
return true;
}
}
/**
* Read one byte from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte readRawByte() throws IOException {
if (bufferPos == bufferSize) {
refillBuffer(true);
}
return buffer[bufferPos++];
}
/**
* Read a fixed size of bytes from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte[] readRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
final byte[] bytes = new byte[size];
System.arraycopy(buffer, bufferPos, bytes, 0, size);
bufferPos += size;
return bytes;
} else if (size < BUFFER_SIZE) {
// Reading more bytes than are in the buffer, but not an excessive number
// of bytes. We can safely allocate the resulting array ahead of time.
// First copy what we have.
final byte[] bytes = new byte[size];
int pos = bufferSize - bufferPos;
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
bufferPos = bufferSize;
// We want to use refillBuffer() and then copy from the buffer into our
// byte array rather than reading directly into our byte array because
// the input may be unbuffered.
refillBuffer(true);
while (size - pos > bufferSize) {
System.arraycopy(buffer, 0, bytes, pos, bufferSize);
pos += bufferSize;
bufferPos = bufferSize;
refillBuffer(true);
}
System.arraycopy(buffer, 0, bytes, pos, size - pos);
bufferPos = size - pos;
return bytes;
} else {
// The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in
// order to trick the app into allocating a lot of memory. We avoid this
// by allocating and reading only a small chunk at a time, so that the
// malicious message must actually *be* extremely large to cause
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
// Remember the buffer markers since we'll have to copy the bytes out of
// it later.
final int originalBufferPos = bufferPos;
final int originalBufferSize = bufferSize;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = 0;
// Read all the rest of the bytes we need.
int sizeLeft = size - (originalBufferSize - originalBufferPos);
final List<byte[]> chunks = new ArrayList<byte[]>();
while (sizeLeft > 0) {
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
int pos = 0;
while (pos < chunk.length) {
final int n = raf.read(chunk, pos, chunk.length - pos);
if (n == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
totalBytesRetired += n;
pos += n;
}
sizeLeft -= chunk.length;
chunks.add(chunk);
}
// OK, got everything. Now concatenate it all into one buffer.
final byte[] bytes = new byte[size];
// Start by copying the leftover bytes from this.buffer.
int pos = originalBufferSize - originalBufferPos;
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
// And now all the chunks.
for (final byte[] chunk : chunks) {
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
pos += chunk.length;
}
// Done.
return bytes;
}
}
/**
* Reads and discards {@code size} bytes.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public void skipRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
bufferPos += size;
} else {
// Skipping more bytes than are in the buffer. First skip what we have.
int pos = bufferSize - bufferPos;
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = 0;
// Then skip directly from the InputStream for the rest.
while (pos < size) {
final int n = raf.skipBytes(size - pos);
if (n <= 0) {
throw InvalidProtocolBufferException.truncatedMessage();
}
pos += n;
totalBytesRetired += n;
}
}
}
public void seek(long pointer) throws IOException{
if(pointer - totalBytesRetired >= 0 && pointer - totalBytesRetired < bufferSize){
skipRawBytes((int) (pointer - getTotalBytesRead()));
} else {
totalBytesRetired = (int) pointer;
raf.seek(pointer);
bufferPos = 0;
bufferSize = 0;
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,438 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.InputStream;
import java.io.IOException;
import java.util.Map;
/**
* An implementation of {@link Message} that can represent arbitrary types,
* given a {@link Descriptors.Descriptor}.
*
* @author kenton@google.com Kenton Varda
*/
public final class DynamicMessage extends AbstractMessage {
private final Descriptor type;
private final FieldSet<FieldDescriptor> fields;
private final UnknownFieldSet unknownFields;
private int memoizedSize = -1;
/**
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
*/
private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
UnknownFieldSet unknownFields) {
this.type = type;
this.fields = fields;
this.unknownFields = unknownFields;
}
/**
* Get a {@code DynamicMessage} representing the default instance of the
* given type.
*/
public static DynamicMessage getDefaultInstance(Descriptor type) {
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
UnknownFieldSet.getDefaultInstance());
}
/** Parse a message of the given type from the given input stream. */
public static DynamicMessage parseFrom(Descriptor type,
CodedInputStream input)
throws IOException {
return newBuilder(type).mergeFrom(input).buildParsed();
}
/** Parse a message of the given type from the given input stream. */
public static DynamicMessage parseFrom(
Descriptor type,
CodedInputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, ByteString data)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, ByteString data,
ExtensionRegistry extensionRegistry)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, byte[] data)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, byte[] data,
ExtensionRegistry extensionRegistry)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
}
/** Parse a message of the given type from {@code input} and return it. */
public static DynamicMessage parseFrom(Descriptor type, InputStream input)
throws IOException {
return newBuilder(type).mergeFrom(input).buildParsed();
}
/** Parse a message of the given type from {@code input} and return it. */
public static DynamicMessage parseFrom(Descriptor type, InputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
}
/** Construct a {@link Message.Builder} for the given type. */
public static Builder newBuilder(Descriptor type) {
return new Builder(type);
}
/**
* Construct a {@link Message.Builder} for a message of the same type as
* {@code prototype}, and initialize it with {@code prototype}'s contents.
*/
public static Builder newBuilder(Message prototype) {
return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
}
// -----------------------------------------------------------------
// Implementation of Message interface.
public Descriptor getDescriptorForType() {
return type;
}
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
private static boolean isInitialized(Descriptor type,
FieldSet<FieldDescriptor> fields) {
// Check that all required fields are present.
for (final FieldDescriptor field : type.getFields()) {
if (field.isRequired()) {
if (!fields.hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
return fields.isInitialized();
}
public boolean isInitialized() {
return isInitialized(type, fields);
}
public void writeTo(CodedOutputStream output) throws IOException {
if (type.getOptions().getMessageSetWireFormat()) {
fields.writeMessageSetTo(output);
unknownFields.writeAsMessageSetTo(output);
} else {
fields.writeTo(output);
unknownFields.writeTo(output);
}
}
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
if (type.getOptions().getMessageSetWireFormat()) {
size = fields.getMessageSetSerializedSize();
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size = fields.getSerializedSize();
size += unknownFields.getSerializedSize();
}
memoizedSize = size;
return size;
}
public Builder newBuilderForType() {
return new Builder(type);
}
public Builder toBuilder() {
return newBuilderForType().mergeFrom(this);
}
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
throw new IllegalArgumentException(
"FieldDescriptor does not match message type.");
}
}
// =================================================================
/**
* Builder for {@link DynamicMessage}s.
*/
public static final class Builder extends AbstractMessage.Builder<Builder> {
private final Descriptor type;
private FieldSet<FieldDescriptor> fields;
private UnknownFieldSet unknownFields;
/** Construct a {@code Builder} for the given type. */
private Builder(Descriptor type) {
this.type = type;
this.fields = FieldSet.newFieldSet();
this.unknownFields = UnknownFieldSet.getDefaultInstance();
}
// ---------------------------------------------------------------
// Implementation of Message.Builder interface.
public Builder clear() {
if (fields == null) {
throw new IllegalStateException("Cannot call clear() after build().");
}
fields.clear();
return this;
}
public Builder mergeFrom(Message other) {
if (other instanceof DynamicMessage) {
// This should be somewhat faster than calling super.mergeFrom().
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
if (otherDynamicMessage.type != type) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
fields.mergeFrom(otherDynamicMessage.fields);
mergeUnknownFields(otherDynamicMessage.unknownFields);
return this;
} else {
return super.mergeFrom(other);
}
}
public DynamicMessage build() {
// If fields == null, we'll throw an appropriate exception later.
if (fields != null && !isInitialized()) {
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields));
}
return buildPartial();
}
/**
* Helper for DynamicMessage.parseFrom() methods to call. Throws
* {@link InvalidProtocolBufferException} instead of
* {@link UninitializedMessageException}.
*/
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields))
.asInvalidProtocolBufferException();
}
return buildPartial();
}
public DynamicMessage buildPartial() {
if (fields == null) {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
fields.makeImmutable();
DynamicMessage result =
new DynamicMessage(type, fields, unknownFields);
fields = null;
unknownFields = null;
return result;
}
public Builder clone() {
Builder result = new Builder(type);
result.fields.mergeFrom(fields);
return result;
}
public boolean isInitialized() {
return DynamicMessage.isInitialized(type, fields);
}
public Descriptor getDescriptorForType() {
return type;
}
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
public Builder newBuilderForField(FieldDescriptor field) {
verifyContainingType(field);
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"newBuilderForField is only valid for fields with message type.");
}
return new Builder(field.getMessageType());
}
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}
public Builder setField(FieldDescriptor field, Object value) {
verifyContainingType(field);
fields.setField(field, value);
return this;
}
public Builder clearField(FieldDescriptor field) {
verifyContainingType(field);
fields.clearField(field);
return this;
}
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
public Builder setRepeatedField(FieldDescriptor field,
int index, Object value) {
verifyContainingType(field);
fields.setRepeatedField(field, index, value);
return this;
}
public Builder addRepeatedField(FieldDescriptor field, Object value) {
verifyContainingType(field);
fields.addRepeatedField(field, value);
return this;
}
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
this.unknownFields = unknownFields;
return this;
}
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
this.unknownFields =
UnknownFieldSet.newBuilder(this.unknownFields)
.mergeFrom(unknownFields)
.build();
return this;
}
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
throw new IllegalArgumentException(
"FieldDescriptor does not match message type.");
}
}
}
}

View file

@ -0,0 +1,266 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A table of known extensions, searchable by name or field number. When
* parsing a protocol message that might have extensions, you must provide
* an {@code ExtensionRegistry} in which you have registered any extensions
* that you want to be able to parse. Otherwise, those extensions will just
* be treated like unknown fields.
*
* <p>For example, if you had the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* Then you might write code like:
*
* <pre>
* ExtensionRegistry registry = ExtensionRegistry.newInstance();
* registry.add(MyProto.bar);
* MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
* </pre>
*
* <p>Background:
*
* <p>You might wonder why this is necessary. Two alternatives might come to
* mind. First, you might imagine a system where generated extensions are
* automatically registered when their containing classes are loaded. This
* is a popular technique, but is bad design; among other things, it creates a
* situation where behavior can change depending on what classes happen to be
* loaded. It also introduces a security vulnerability, because an
* unprivileged class could cause its code to be called unexpectedly from a
* privileged class by registering itself as an extension of the right type.
*
* <p>Another option you might consider is lazy parsing: do not parse an
* extension until it is first requested, at which point the caller must
* provide a type to use. This introduces a different set of problems. First,
* it would require a mutex lock any time an extension was accessed, which
* would be slow. Second, corrupt data would not be detected until first
* access, at which point it would be much harder to deal with it. Third, it
* could violate the expectation that message objects are immutable, since the
* type provided could be any arbitrary message class. An unprivileged user
* could take advantage of this to inject a mutable object into a message
* belonging to privileged code and create mischief.
*
* @author kenton@google.com Kenton Varda
*/
public final class ExtensionRegistry extends ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistry newInstance() {
return new ExtensionRegistry();
}
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistry getEmptyRegistry() {
return EMPTY;
}
/** Returns an unmodifiable view of the registry. */
@Override
public ExtensionRegistry getUnmodifiable() {
return new ExtensionRegistry(this);
}
/** A (Descriptor, Message) pair, returned by lookup methods. */
public static final class ExtensionInfo {
/** The extension's descriptor. */
public final FieldDescriptor descriptor;
/**
* A default instance of the extension's type, if it has a message type.
* Otherwise, {@code null}.
*/
public final Message defaultInstance;
private ExtensionInfo(final FieldDescriptor descriptor) {
this.descriptor = descriptor;
defaultInstance = null;
}
private ExtensionInfo(final FieldDescriptor descriptor,
final Message defaultInstance) {
this.descriptor = descriptor;
this.defaultInstance = defaultInstance;
}
}
/**
* Find an extension by fully-qualified field name, in the proto namespace.
* I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
* a match is found.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByName(final String fullName) {
return extensionsByName.get(fullName);
}
/**
* Find an extension by containing type and field number.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
final int fieldNumber) {
return extensionsByNumber.get(
new DescriptorIntPair(containingType, fieldNumber));
}
/** Add an extension from a generated file to the registry. */
public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
if (extension.getDescriptor().getJavaType() ==
FieldDescriptor.JavaType.MESSAGE) {
if (extension.getMessageDefaultInstance() == null) {
throw new IllegalStateException(
"Registered message-type extension had null default instance: " +
extension.getDescriptor().getFullName());
}
add(new ExtensionInfo(extension.getDescriptor(),
extension.getMessageDefaultInstance()));
} else {
add(new ExtensionInfo(extension.getDescriptor(), null));
}
}
/** Add a non-message-type extension to the registry by descriptor. */
public void add(final FieldDescriptor type) {
if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() must be provided a default instance when " +
"adding an embedded message extension.");
}
add(new ExtensionInfo(type, null));
}
/** Add a message-type extension to the registry by descriptor. */
public void add(final FieldDescriptor type, final Message defaultInstance) {
if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() provided a default instance for a " +
"non-message extension.");
}
add(new ExtensionInfo(type, defaultInstance));
}
// =================================================================
// Private stuff.
private ExtensionRegistry() {
this.extensionsByName = new HashMap<String, ExtensionInfo>();
this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
}
private ExtensionRegistry(ExtensionRegistry other) {
super(other);
this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
private final Map<String, ExtensionInfo> extensionsByName;
private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
private ExtensionRegistry(boolean empty) {
super(ExtensionRegistryLite.getEmptyRegistry());
this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
this.extensionsByNumber =
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
}
private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
private void add(final ExtensionInfo extension) {
if (!extension.descriptor.isExtension()) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
"(non-extension) field.");
}
extensionsByName.put(extension.descriptor.getFullName(), extension);
extensionsByNumber.put(
new DescriptorIntPair(extension.descriptor.getContainingType(),
extension.descriptor.getNumber()),
extension);
final FieldDescriptor field = extension.descriptor;
if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
field.isOptional() &&
field.getExtensionScope() == field.getMessageType()) {
// This is an extension of a MessageSet type defined within the extension
// type's own scope. For backwards-compatibility, allow it to be looked
// up by type name.
extensionsByName.put(field.getMessageType().getFullName(), extension);
}
}
/** A (GenericDescriptor, int) pair, used as a map key. */
private static final class DescriptorIntPair {
private final Descriptor descriptor;
private final int number;
DescriptorIntPair(final Descriptor descriptor, final int number) {
this.descriptor = descriptor;
this.number = number;
}
@Override
public int hashCode() {
return descriptor.hashCode() * ((1 << 16) - 1) + number;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof DescriptorIntPair)) {
return false;
}
final DescriptorIntPair other = (DescriptorIntPair)obj;
return descriptor == other.descriptor && number == other.number;
}
}
}

View file

@ -0,0 +1,169 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
* <p>
* If all of your types are lite types, then you only need to use
* {@code ExtensionRegistryLite}. Similarly, if all your types are regular
* types, then you only need {@link ExtensionRegistry}. Typically it does not
* make sense to mix the two, since if you have any regular types in your
* program, you then require the full runtime and lose all the benefits of
* the lite runtime, so you might as well make all your types be regular types.
* However, in some cases (e.g. when depending on multiple third-patry libraries
* where one uses lite types and one uses regular), you may find yourself
* wanting to mix the two. In this case things get more complicated.
* <p>
* There are three factors to consider: Whether the type being extended is
* lite, whether the embedded type (in the case of a message-typed extension)
* is lite, and whether the extension itself is lite. Since all three are
* declared in different files, they could all be different. Here are all
* the combinations and which type of registry to use:
* <pre>
* Extended type Inner type Extension Use registry
* =======================================================================
* lite lite lite ExtensionRegistryLite
* lite regular lite ExtensionRegistry
* regular regular regular ExtensionRegistry
* all other combinations not supported
* </pre>
* <p>
* Note that just as regular types are not allowed to contain lite-type fields,
* they are also not allowed to contain lite-type extensions. This is because
* regular types must be fully accessible via reflection, which in turn means
* that all the inner messages must also support reflection. On the other hand,
* since regular types implement the entire lite interface, there is no problem
* with embedding regular types inside lite types.
*
* @author kenton@google.com Kenton Varda
*/
public class ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistryLite newInstance() {
return new ExtensionRegistryLite();
}
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistryLite getEmptyRegistry() {
return EMPTY;
}
/** Returns an unmodifiable view of the registry. */
public ExtensionRegistryLite getUnmodifiable() {
return new ExtensionRegistryLite(this);
}
/**
* Find an extension by containing type and field number.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
@SuppressWarnings("unchecked")
public <ContainingType extends MessageLite>
GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
findLiteExtensionByNumber(
final ContainingType containingTypeDefaultInstance,
final int fieldNumber) {
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
extensionsByNumber.get(
new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
}
/** Add an extension from a lite generated file to the registry. */
public final void add(
final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
extensionsByNumber.put(
new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
extension.getNumber()),
extension);
}
// =================================================================
// Private stuff.
// Constructors are package-private so that ExtensionRegistry can subclass
// this.
ExtensionRegistryLite() {
this.extensionsByNumber =
new HashMap<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>();
}
ExtensionRegistryLite(ExtensionRegistryLite other) {
if (other == EMPTY) {
this.extensionsByNumber = Collections.emptyMap();
} else {
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
}
private final Map<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>
extensionsByNumber;
private ExtensionRegistryLite(boolean empty) {
this.extensionsByNumber = Collections.emptyMap();
}
private static final ExtensionRegistryLite EMPTY =
new ExtensionRegistryLite(true);
/** A (Object, int) pair, used as a map key. */
private static final class ObjectIntPair {
private final Object object;
private final int number;
ObjectIntPair(final Object object, final int number) {
this.object = object;
this.number = number;
}
@Override
public int hashCode() {
return System.identityHashCode(object) * ((1 << 16) - 1) + number;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof ObjectIntPair)) {
return false;
}
final ObjectIntPair other = (ObjectIntPair)obj;
return object == other.object && number == other.number;
}
}
}

View file

@ -0,0 +1,715 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
/**
* A class which represents an arbitrary set of fields of some message type.
* This is used to implement {@link DynamicMessage}, and also to represent
* extensions in {@link GeneratedMessage}. This class is package-private,
* since outside users should probably be using {@link DynamicMessage}.
*
* @author kenton@google.com Kenton Varda
*/
final class FieldSet<FieldDescriptorType extends
FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
/**
* Interface for a FieldDescriptor or lite extension descriptor. This
* prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
*/
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
extends Comparable<T> {
int getNumber();
WireFormat.FieldType getLiteType();
WireFormat.JavaType getLiteJavaType();
boolean isRepeated();
boolean isPacked();
Internal.EnumLiteMap<?> getEnumType();
// If getLiteJavaType() == MESSAGE, this merges a message object of the
// type into a builder of the type. Returns {@code to}.
MessageLite.Builder internalMergeFrom(
MessageLite.Builder to, MessageLite from);
}
private Map<FieldDescriptorType, Object> fields;
/** Construct a new FieldSet. */
private FieldSet() {
// Use a TreeMap because fields need to be in canonical order when
// serializing.
// TODO(kenton): Maybe use some sort of sparse array instead? It would
// even make sense to store the first 16 or so tags in a flat array
// to make DynamicMessage faster.
fields = new TreeMap<FieldDescriptorType, Object>();
}
/**
* Construct an empty FieldSet. This is only used to initialize
* DEFAULT_INSTANCE.
*/
private FieldSet(final boolean dummy) {
this.fields = Collections.emptyMap();
}
/** Construct a new FieldSet. */
public static <T extends FieldSet.FieldDescriptorLite<T>>
FieldSet<T> newFieldSet() {
return new FieldSet<T>();
}
/** Get an immutable empty FieldSet. */
@SuppressWarnings("unchecked")
public static <T extends FieldSet.FieldDescriptorLite<T>>
FieldSet<T> emptySet() {
return DEFAULT_INSTANCE;
}
@SuppressWarnings("unchecked")
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
/** Make this FieldSet immutable from this point forward. */
@SuppressWarnings("unchecked")
public void makeImmutable() {
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
if (entry.getKey().isRepeated()) {
final List value = (List)entry.getValue();
fields.put(entry.getKey(), Collections.unmodifiableList(value));
}
}
fields = Collections.unmodifiableMap(fields);
}
// =================================================================
/** See {@link Message.Builder#clear()}. */
public void clear() {
fields.clear();
}
/**
* Get a simple map containing all the fields.
*/
public Map<FieldDescriptorType, Object> getAllFields() {
return Collections.unmodifiableMap(fields);
}
/**
* Get an iterator to the field map. This iterator should not be leaked
* out of the protobuf library as it is not protected from mutation.
*/
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
return fields.entrySet().iterator();
}
/**
* Useful for implementing
* {@link Message#hasField(Descriptors.FieldDescriptor)}.
*/
public boolean hasField(final FieldDescriptorType descriptor) {
if (descriptor.isRepeated()) {
throw new IllegalArgumentException(
"hasField() can only be called on non-repeated fields.");
}
return fields.get(descriptor) != null;
}
/**
* Useful for implementing
* {@link Message#getField(Descriptors.FieldDescriptor)}. This method
* returns {@code null} if the field is not set; in this case it is up
* to the caller to fetch the field's default value.
*/
public Object getField(final FieldDescriptorType descriptor) {
return fields.get(descriptor);
}
/**
* Useful for implementing
* {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
*/
@SuppressWarnings("unchecked")
public void setField(final FieldDescriptorType descriptor,
Object value) {
if (descriptor.isRepeated()) {
if (!(value instanceof List)) {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
// Wrap the contents in a new list so that the caller cannot change
// the list's contents after setting it.
final List newList = new ArrayList();
newList.addAll((List)value);
for (final Object element : newList) {
verifyType(descriptor.getLiteType(), element);
}
value = newList;
} else {
verifyType(descriptor.getLiteType(), value);
}
fields.put(descriptor, value);
}
/**
* Useful for implementing
* {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
*/
public void clearField(final FieldDescriptorType descriptor) {
fields.remove(descriptor);
}
/**
* Useful for implementing
* {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
*/
public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = fields.get(descriptor);
if (value == null) {
return 0;
} else {
return ((List<?>) value).size();
}
}
/**
* Useful for implementing
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
*/
@SuppressWarnings("unchecked")
public Object getRepeatedField(final FieldDescriptorType descriptor,
final int index) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = fields.get(descriptor);
if (value == null) {
throw new IndexOutOfBoundsException();
} else {
return ((List) value).get(index);
}
}
/**
* Useful for implementing
* {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
*/
@SuppressWarnings("unchecked")
public void setRepeatedField(final FieldDescriptorType descriptor,
final int index,
final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object list = fields.get(descriptor);
if (list == null) {
throw new IndexOutOfBoundsException();
}
verifyType(descriptor.getLiteType(), value);
((List) list).set(index, value);
}
/**
* Useful for implementing
* {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
*/
@SuppressWarnings("unchecked")
public void addRepeatedField(final FieldDescriptorType descriptor,
final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"addRepeatedField() can only be called on repeated fields.");
}
verifyType(descriptor.getLiteType(), value);
final Object existingValue = fields.get(descriptor);
List list;
if (existingValue == null) {
list = new ArrayList();
fields.put(descriptor, list);
} else {
list = (List) existingValue;
}
list.add(value);
}
/**
* Verifies that the given object is of the correct type to be a valid
* value for the given field. (For repeated fields, this checks if the
* object is the right type to be one element of the field.)
*
* @throws IllegalArgumentException The value is not of the right type.
*/
private static void verifyType(final WireFormat.FieldType type,
final Object value) {
if (value == null) {
throw new NullPointerException();
}
boolean isValid = false;
switch (type.getJavaType()) {
case INT: isValid = value instanceof Integer ; break;
case LONG: isValid = value instanceof Long ; break;
case FLOAT: isValid = value instanceof Float ; break;
case DOUBLE: isValid = value instanceof Double ; break;
case BOOLEAN: isValid = value instanceof Boolean ; break;
case STRING: isValid = value instanceof String ; break;
case BYTE_STRING: isValid = value instanceof ByteString; break;
case ENUM:
// TODO(kenton): Caller must do type checking here, I guess.
isValid = value instanceof Internal.EnumLite;
break;
case MESSAGE:
// TODO(kenton): Caller must do type checking here, I guess.
isValid = value instanceof MessageLite;
break;
}
if (!isValid) {
// TODO(kenton): When chaining calls to setField(), it can be hard to
// tell from the stack trace which exact call failed, since the whole
// chain is considered one line of code. It would be nice to print
// more information here, e.g. naming the field. We used to do that.
// But we can't now that FieldSet doesn't use descriptors. Maybe this
// isn't a big deal, though, since it would only really apply when using
// reflection and generally people don't chain reflection setters.
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
// =================================================================
// Parsing and serialization
/**
* See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
* itself does not have any way of knowing about required fields that
* aren't actually present in the set, it is up to the caller to check
* that all required fields are present.
*/
@SuppressWarnings("unchecked")
public boolean isInitialized() {
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
if (descriptor.isRepeated()) {
for (final MessageLite element:
(List<MessageLite>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
if (!((MessageLite) entry.getValue()).isInitialized()) {
return false;
}
}
}
}
return true;
}
/**
* Given a field type, return the wire type.
*
* @returns One of the {@code WIRETYPE_} constants defined in
* {@link WireFormat}.
*/
static int getWireFormatForFieldType(final WireFormat.FieldType type,
boolean isPacked) {
if (isPacked) {
return WireFormat.WIRETYPE_LENGTH_DELIMITED;
} else {
return type.getWireType();
}
}
/**
* Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
*/
@SuppressWarnings("unchecked")
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
for (final Map.Entry<FieldDescriptorType, Object> entry:
other.fields.entrySet()) {
final FieldDescriptorType descriptor = entry.getKey();
final Object otherValue = entry.getValue();
if (descriptor.isRepeated()) {
Object value = fields.get(descriptor);
if (value == null) {
// Our list is empty, but we still need to make a defensive copy of
// the other list since we don't know if the other FieldSet is still
// mutable.
fields.put(descriptor, new ArrayList((List) otherValue));
} else {
// Concatenate the lists.
((List) value).addAll((List) otherValue);
}
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
Object value = fields.get(descriptor);
if (value == null) {
fields.put(descriptor, otherValue);
} else {
// Merge the messages.
fields.put(descriptor,
descriptor.internalMergeFrom(
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
.build());
}
} else {
fields.put(descriptor, otherValue);
}
}
}
// TODO(kenton): Move static parsing and serialization methods into some
// other class. Probably WireFormat.
/**
* Read a field of any primitive type from a CodedInputStream. Enums,
* groups, and embedded messages are not handled by this method.
*
* @param input The stream from which to read.
* @param type Declared type of the field.
* @return An object representing the field's value, of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public static Object readPrimitiveField(
CodedInputStream input,
final WireFormat.FieldType type) throws IOException {
switch (type) {
case DOUBLE : return input.readDouble ();
case FLOAT : return input.readFloat ();
case INT64 : return input.readInt64 ();
case UINT64 : return input.readUInt64 ();
case INT32 : return input.readInt32 ();
case FIXED64 : return input.readFixed64 ();
case FIXED32 : return input.readFixed32 ();
case BOOL : return input.readBool ();
case STRING : return input.readString ();
case BYTES : return input.readBytes ();
case UINT32 : return input.readUInt32 ();
case SFIXED32: return input.readSFixed32();
case SFIXED64: return input.readSFixed64();
case SINT32 : return input.readSInt32 ();
case SINT64 : return input.readSInt64 ();
case GROUP:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle nested groups.");
case MESSAGE:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle embedded messages.");
case ENUM:
// We don't handle enums because we don't know what to do if the
// value is not recognized.
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle enums.");
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
/** See {@link Message#writeTo(CodedOutputStream)}. */
public void writeTo(final CodedOutputStream output)
throws IOException {
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
writeField(entry.getKey(), entry.getValue(), output);
}
}
/**
* Like {@link #writeTo} but uses MessageSet wire format.
*/
public void writeMessageSetTo(final CodedOutputStream output)
throws IOException {
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
!descriptor.isRepeated() && !descriptor.isPacked()) {
output.writeMessageSetExtension(entry.getKey().getNumber(),
(MessageLite) entry.getValue());
} else {
writeField(descriptor, entry.getValue(), output);
}
}
}
/**
* Write a single tag-value pair to the stream.
*
* @param output The output stream.
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static void writeElement(final CodedOutputStream output,
final WireFormat.FieldType type,
final int number,
final Object value) throws IOException {
// Special case for groups, which need a start and end tag; other fields
// can just use writeTag() and writeFieldNoTag().
if (type == WireFormat.FieldType.GROUP) {
output.writeGroup(number, (MessageLite) value);
} else {
output.writeTag(number, getWireFormatForFieldType(type, false));
writeElementNoTag(output, type, value);
}
}
/**
* Write a field of arbitrary type, without its tag, to the stream.
*
* @param output The output stream.
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static void writeElementNoTag(
final CodedOutputStream output,
final WireFormat.FieldType type,
final Object value) throws IOException {
switch (type) {
case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
case FLOAT : output.writeFloatNoTag ((Float ) value); break;
case INT64 : output.writeInt64NoTag ((Long ) value); break;
case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
case INT32 : output.writeInt32NoTag ((Integer ) value); break;
case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
case STRING : output.writeStringNoTag ((String ) value); break;
case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
case ENUM:
output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
break;
}
}
/** Write a single field. */
@SuppressWarnings("unchecked")
public static void writeField(final FieldDescriptorLite<?> descriptor,
final Object value,
final CodedOutputStream output)
throws IOException {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
final List valueList = (List)value;
if (descriptor.isPacked()) {
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
// Compute the total data size so the length can be written.
int dataSize = 0;
for (final Object element : valueList) {
dataSize += computeElementSizeNoTag(type, element);
}
output.writeRawVarint32(dataSize);
// Write the data itself, without any tags.
for (final Object element : valueList) {
writeElementNoTag(output, type, element);
}
} else {
for (final Object element : valueList) {
writeElement(output, type, number, element);
}
}
} else {
writeElement(output, type, number, value);
}
}
/**
* See {@link Message#getSerializedSize()}. It's up to the caller to cache
* the resulting size if desired.
*/
public int getSerializedSize() {
int size = 0;
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
size += computeFieldSize(entry.getKey(), entry.getValue());
}
return size;
}
/**
* Like {@link #getSerializedSize} but uses MessageSet wire format.
*/
public int getMessageSetSerializedSize() {
int size = 0;
for (final Map.Entry<FieldDescriptorType, Object> entry:
fields.entrySet()) {
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
!descriptor.isRepeated() && !descriptor.isPacked()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
entry.getKey().getNumber(), (MessageLite) entry.getValue());
} else {
size += computeFieldSize(descriptor, entry.getValue());
}
}
return size;
}
/**
* Compute the number of bytes that would be needed to encode a
* single tag/value pair of arbitrary type.
*
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static int computeElementSize(
final WireFormat.FieldType type,
final int number, final Object value) {
int tagSize = CodedOutputStream.computeTagSize(number);
if (type == WireFormat.FieldType.GROUP) {
tagSize *= 2;
}
return tagSize + computeElementSizeNoTag(type, value);
}
/**
* Compute the number of bytes that would be needed to encode a
* particular value of arbitrary type, excluding tag.
*
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static int computeElementSizeNoTag(
final WireFormat.FieldType type, final Object value) {
switch (type) {
// Note: Minor violation of 80-char limit rule here because this would
// actually be harder to read if we wrapped the lines.
case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
case ENUM:
return CodedOutputStream.computeEnumSizeNoTag(
((Internal.EnumLite) value).getNumber());
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
/**
* Compute the number of bytes needed to encode a particular field.
*/
@SuppressWarnings("unchecked")
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
final Object value) {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
if (descriptor.isPacked()) {
int dataSize = 0;
for (final Object element : (List)value) {
dataSize += computeElementSizeNoTag(type, element);
}
return dataSize +
CodedOutputStream.computeTagSize(number) +
CodedOutputStream.computeRawVarint32Size(dataSize);
} else {
int size = 0;
for (final Object element : (List)value) {
size += computeElementSize(type, number, element);
}
return size;
}
} else {
return computeElementSize(type, number, value);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,567 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Lite version of {@link GeneratedMessage}.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class GeneratedMessageLite extends AbstractMessageLite {
protected GeneratedMessageLite() {}
@SuppressWarnings("unchecked")
public abstract static class Builder<MessageType extends GeneratedMessageLite,
BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType> {
protected Builder() {}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
/** All subclasses implement this. */
public abstract BuilderType mergeFrom(MessageType message);
// Defined here for return type covariance.
public abstract MessageType getDefaultInstanceForType();
/**
* Get the message being built. We don't just pass this to the
* constructor because it becomes null when build() is called.
*/
protected abstract MessageType internalGetResult();
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
return input.skipField(tag);
}
}
// =================================================================
// Extensions-related stuff
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
*/
public abstract static class ExtendableMessage<
MessageType extends ExtendableMessage<MessageType>>
extends GeneratedMessageLite {
protected ExtendableMessage() {}
private final FieldSet<ExtensionDescriptor> extensions =
FieldSet.newFieldSet();
private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
getDefaultInstanceForType()) {
// This can only happen if someone uses unchecked operations.
throw new IllegalArgumentException(
"This extension is for a different message type. Please make " +
"sure that you are not suppressing any generics type warnings.");
}
}
/** Check if a singular extension is present. */
public final boolean hasExtension(
final GeneratedExtension<MessageType, ?> extension) {
verifyExtensionContainingType(extension);
return extensions.hasField(extension.descriptor);
}
/** Get the number of elements in a repeated extension. */
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
verifyExtensionContainingType(extension);
return extensions.getRepeatedFieldCount(extension.descriptor);
}
/** Get the value of an extension. */
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
final Object value = extensions.getField(extension.descriptor);
if (value == null) {
return extension.defaultValue;
} else {
return (Type) value;
}
}
/** Get one element of a repeated extension. */
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
verifyExtensionContainingType(extension);
return (Type) extensions.getRepeatedField(extension.descriptor, index);
}
/** Called by subclasses to check if all extensions are initialized. */
protected boolean extensionsAreInitialized() {
return extensions.isInitialized();
}
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
* (sorted by field number) order. ExtensionWriter helps us write
* individual ranges of extensions at once.
*/
protected class ExtensionWriter {
// Imagine how much simpler this code would be if Java iterators had
// a way to get the next element without advancing the iterator.
private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
extensions.iterator();
private Map.Entry<ExtensionDescriptor, Object> next;
private final boolean messageSetWireFormat;
private ExtensionWriter(boolean messageSetWireFormat) {
if (iter.hasNext()) {
next = iter.next();
}
this.messageSetWireFormat = messageSetWireFormat;
}
public void writeUntil(final int end, final CodedOutputStream output)
throws IOException {
while (next != null && next.getKey().getNumber() < end) {
ExtensionDescriptor extension = next.getKey();
if (messageSetWireFormat && extension.getLiteJavaType() ==
WireFormat.JavaType.MESSAGE &&
!extension.isRepeated()) {
output.writeMessageSetExtension(extension.getNumber(),
(MessageLite) next.getValue());
} else {
FieldSet.writeField(extension, next.getValue(), output);
}
if (iter.hasNext()) {
next = iter.next();
} else {
next = null;
}
}
}
}
protected ExtensionWriter newExtensionWriter() {
return new ExtensionWriter(false);
}
protected ExtensionWriter newMessageSetExtensionWriter() {
return new ExtensionWriter(true);
}
/** Called by subclasses to compute the size of extensions. */
protected int extensionsSerializedSize() {
return extensions.getSerializedSize();
}
protected int extensionsSerializedSizeAsMessageSet() {
return extensions.getMessageSetSerializedSize();
}
}
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
*/
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
MessageType extends ExtendableMessage<MessageType>,
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<MessageType, BuilderType> {
protected ExtendableBuilder() {}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
@Override
protected abstract MessageType internalGetResult();
/** Check if a singular extension is present. */
public final boolean hasExtension(
final GeneratedExtension<MessageType, ?> extension) {
return internalGetResult().hasExtension(extension);
}
/** Get the number of elements in a repeated extension. */
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
return internalGetResult().getExtensionCount(extension);
}
/** Get the value of an extension. */
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
return internalGetResult().getExtension(extension);
}
/** Get one element of a repeated extension. */
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
return internalGetResult().getExtension(extension, index);
}
/** Set the value of an extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, Type> extension,
final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.setField(extension.descriptor, value);
return (BuilderType) this;
}
/** Set the value of one element of a repeated extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index, final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.setRepeatedField(extension.descriptor, index, value);
return (BuilderType) this;
}
/** Append a value to a repeated extension. */
public final <Type> BuilderType addExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final Type value) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.addRepeatedField(extension.descriptor, value);
return (BuilderType) this;
}
/** Clear an extension. */
public final <Type> BuilderType clearExtension(
final GeneratedExtension<MessageType, ?> extension) {
final ExtendableMessage<MessageType> message = internalGetResult();
message.verifyExtensionContainingType(extension);
message.extensions.clearField(extension.descriptor);
return (BuilderType) this;
}
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
@Override
protected boolean parseUnknownField(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry,
final int tag) throws IOException {
final FieldSet<ExtensionDescriptor> extensions =
((ExtendableMessage) internalGetResult()).extensions;
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final GeneratedExtension<MessageType, ?> extension =
extensionRegistry.findLiteExtensionByNumber(
getDefaultInstanceForType(), fieldNumber);
boolean unknown = false;
boolean packed = false;
if (extension == null) {
unknown = true; // Unknown field.
} else if (wireType == FieldSet.getWireFormatForFieldType(
extension.descriptor.getLiteType(),
false /* isPacked */)) {
packed = false; // Normal, unpacked value.
} else if (extension.descriptor.isRepeated &&
extension.descriptor.type.isPackable() &&
wireType == FieldSet.getWireFormatForFieldType(
extension.descriptor.getLiteType(),
true /* isPacked */)) {
packed = true; // Packed value.
} else {
unknown = true; // Wrong wire type.
}
if (unknown) { // Unknown field or wrong wire type. Skip.
return input.skipField(tag);
}
if (packed) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value =
extension.descriptor.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
extensions.addRepeatedField(extension.descriptor, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
extensions.addRepeatedField(extension.descriptor, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (extension.descriptor.getLiteJavaType()) {
case MESSAGE: {
MessageLite.Builder subBuilder = null;
if (!extension.descriptor.isRepeated()) {
MessageLite existingValue =
(MessageLite) extensions.getField(extension.descriptor);
if (existingValue != null) {
subBuilder = existingValue.toBuilder();
}
}
if (subBuilder == null) {
subBuilder = extension.messageDefaultInstance.newBuilderForType();
}
if (extension.descriptor.getLiteType() ==
WireFormat.FieldType.GROUP) {
input.readGroup(extension.getNumber(),
subBuilder, extensionRegistry);
} else {
input.readMessage(subBuilder, extensionRegistry);
}
value = subBuilder.build();
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = extension.descriptor.getEnumType()
.findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
break;
}
if (extension.descriptor.isRepeated()) {
extensions.addRepeatedField(extension.descriptor, value);
} else {
extensions.setField(extension.descriptor, value);
}
}
return true;
}
protected final void mergeExtensionFields(final MessageType other) {
((ExtendableMessage) internalGetResult()).extensions.mergeFrom(
((ExtendableMessage) other).extensions);
}
}
// -----------------------------------------------------------------
/** For use by generated code only. */
public static <ContainingType extends MessageLite, Type>
GeneratedExtension<ContainingType, Type>
newGeneratedExtension() {
return new GeneratedExtension<ContainingType, Type>();
}
private static final class ExtensionDescriptor
implements FieldSet.FieldDescriptorLite<
ExtensionDescriptor> {
private ExtensionDescriptor(
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isRepeated,
final boolean isPacked) {
this.enumTypeMap = enumTypeMap;
this.number = number;
this.type = type;
this.isRepeated = isRepeated;
this.isPacked = isPacked;
}
private final Internal.EnumLiteMap<?> enumTypeMap;
private final int number;
private final WireFormat.FieldType type;
private final boolean isRepeated;
private final boolean isPacked;
public int getNumber() {
return number;
}
public WireFormat.FieldType getLiteType() {
return type;
}
public WireFormat.JavaType getLiteJavaType() {
return type.getJavaType();
}
public boolean isRepeated() {
return isRepeated;
}
public boolean isPacked() {
return isPacked;
}
public Internal.EnumLiteMap<?> getEnumType() {
return enumTypeMap;
}
@SuppressWarnings("unchecked")
public MessageLite.Builder internalMergeFrom(
MessageLite.Builder to, MessageLite from) {
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
}
public int compareTo(ExtensionDescriptor other) {
return number - other.number;
}
}
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
* Users should ignore the contents of this class and only use objects of
* this type as parameters to extension accessors and ExtensionRegistry.add().
*/
public static final class GeneratedExtension<
ContainingType extends MessageLite, Type> {
// We can't always initialize a GeneratedExtension when we first construct
// it due to initialization order difficulties (namely, the default
// instances may not have been constructed yet). So, we construct an
// uninitialized GeneratedExtension once, then call internalInit() on it
// later. Generated code will always call internalInit() on all extensions
// as part of the static initialization code, and internalInit() throws an
// exception if called more than once, so this method is useless to users.
private GeneratedExtension() {}
private void internalInit(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final ExtensionDescriptor descriptor) {
this.containingTypeDefaultInstance = containingTypeDefaultInstance;
this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor;
}
/** For use by generated code only. */
public void internalInitSingular(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type) {
internalInit(
containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
new ExtensionDescriptor(enumTypeMap, number, type,
false /* isRepeated */, false /* isPacked */));
}
/** For use by generated code only. */
@SuppressWarnings("unchecked")
public void internalInitRepeated(
final ContainingType containingTypeDefaultInstance,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isPacked) {
internalInit(
containingTypeDefaultInstance, (Type) Collections.emptyList(),
messageDefaultInstance,
new ExtensionDescriptor(
enumTypeMap, number, type, true /* isRepeated */, isPacked));
}
private ContainingType containingTypeDefaultInstance;
private Type defaultValue;
private MessageLite messageDefaultInstance;
private ExtensionDescriptor descriptor;
/**
* Default instance of the type being extended, used to identify that type.
*/
public ContainingType getContainingTypeDefaultInstance() {
return containingTypeDefaultInstance;
}
/** Get the field number. */
public int getNumber() {
return descriptor.getNumber();
}
/**
* If the extension is an embedded message, this is the default instance of
* that type.
*/
public MessageLite getMessageDefaultInstance() {
return messageDefaultInstance;
}
}
}

View file

@ -0,0 +1,121 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
/**
* The classes contained within are used internally by the Protocol Buffer
* library and generated message implementations. They are public only because
* those generated messages do not reside in the {@code protobuf} package.
* Others should not use this class directly.
*
* @author kenton@google.com (Kenton Varda)
*/
public class Internal {
/**
* Helper called by generated code to construct default values for string
* fields.
* <p>
* The protocol compiler does not actually contain a UTF-8 decoder -- it
* just pushes UTF-8-encoded text around without touching it. The one place
* where this presents a problem is when generating Java string literals.
* Unicode characters in the string literal would normally need to be encoded
* using a Unicode escape sequence, which would require decoding them.
* To get around this, protoc instead embeds the UTF-8 bytes into the
* generated code and leaves it to the runtime library to decode them.
* <p>
* It gets worse, though. If protoc just generated a byte array, like:
* new byte[] {0x12, 0x34, 0x56, 0x78}
* Java actually generates *code* which allocates an array and then fills
* in each value. This is much less efficient than just embedding the bytes
* directly into the bytecode. To get around this, we need another
* work-around. String literals are embedded directly, so protoc actually
* generates a string literal corresponding to the bytes. The easiest way
* to do this is to use the ISO-8859-1 character set, which corresponds to
* the first 256 characters of the Unicode range. Protoc can then use
* good old CEscape to generate the string.
* <p>
* So we have a string literal which represents a set of bytes which
* represents another string. This function -- stringDefaultValue --
* converts from the generated string to the string we actually want. The
* generated code calls this automatically.
*/
public static String stringDefaultValue(String bytes) {
try {
return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// both of the above character sets.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Helper called by generated code to construct default values for bytes
* fields.
* <p>
* This is a lot like {@link #stringDefaultValue}, but for bytes fields.
* In this case we only need the second of the two hacks -- allowing us to
* embed raw bytes as a string literal with ISO-8859-1 encoding.
*/
public static ByteString bytesDefaultValue(String bytes) {
try {
return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// ISO-8859-1.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Interface for an enum value or value descriptor, to be used in FieldSet.
* The lite library stores enum values directly in FieldSets but the full
* library stores EnumValueDescriptors in order to better support reflection.
*/
public interface EnumLite {
int getNumber();
}
/**
* Interface for an object which maps integers to {@link EnumLite}s.
* {@link Descriptors.EnumDescriptor} implements this interface by mapping
* numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
* every generated enum type has a static method internalGetValueMap() which
* returns an implementation of this type that maps numbers to enum values.
*/
public interface EnumLiteMap<T extends EnumLite> {
T findValueByNumber(int number);
}
}

View file

@ -0,0 +1,93 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
/**
* Thrown when a protocol message being parsed is invalid in some way,
* e.g. it contains a malformed varint or a negative byte length.
*
* @author kenton@google.com Kenton Varda
*/
public class InvalidProtocolBufferException extends IOException {
private static final long serialVersionUID = -1616151763072450476L;
public InvalidProtocolBufferException(final String description) {
super(description);
}
static InvalidProtocolBufferException truncatedMessage() {
return new InvalidProtocolBufferException(
"While parsing a protocol message, the input ended unexpectedly " +
"in the middle of a field. This could mean either than the " +
"input has been truncated or that an embedded message " +
"misreported its own length.");
}
static InvalidProtocolBufferException negativeSize() {
return new InvalidProtocolBufferException(
"CodedInputStream encountered an embedded string or message " +
"which claimed to have negative size.");
}
static InvalidProtocolBufferException malformedVarint() {
return new InvalidProtocolBufferException(
"CodedInputStream encountered a malformed varint.");
}
static InvalidProtocolBufferException invalidTag() {
return new InvalidProtocolBufferException(
"Protocol message contained an invalid tag (zero).");
}
static InvalidProtocolBufferException invalidEndTag() {
return new InvalidProtocolBufferException(
"Protocol message end-group tag did not match expected tag.");
}
static InvalidProtocolBufferException invalidWireType() {
return new InvalidProtocolBufferException(
"Protocol message tag had invalid wire type.");
}
static InvalidProtocolBufferException recursionLimitExceeded() {
return new InvalidProtocolBufferException(
"Protocol message had too many levels of nesting. May be malicious. " +
"Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
}
static InvalidProtocolBufferException sizeLimitExceeded() {
return new InvalidProtocolBufferException(
"Protocol message was too large. May be malicious. " +
"Use CodedInputStream.setSizeLimit() to increase the size limit.");
}
}

View file

@ -0,0 +1,305 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
// mergeFrom*() could return BuilderType for better type-safety.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Abstract interface implemented by Protocol Message objects.
* <p>
* See also {@link MessageLite}, which defines most of the methods that typical
* users care about. {@link Message} adds to it methods that are not available
* in the "lite" runtime. The biggest added features are introspection and
* reflection -- i.e., getting descriptors for the message type and accessing
* the field values dynamically.
*
* @author kenton@google.com Kenton Varda
*/
public interface Message extends MessageLite {
/**
* Get the message's type's descriptor. This differs from the
* {@code getDescriptor()} method of generated message classes in that
* this method is an abstract method of the {@code Message} interface
* whereas {@code getDescriptor()} is a static method of a specific class.
* They return the same thing.
*/
Descriptors.Descriptor getDescriptorForType();
// (From MessageLite, re-declared here only for return type covariance.)
Message getDefaultInstanceForType();
/**
* Returns a collection of all the fields in this message which are set
* and their corresponding values. A singular ("required" or "optional")
* field is set iff hasField() returns true for that field. A "repeated"
* field is set iff getRepeatedFieldSize() is greater than zero. The
* values are exactly what would be returned by calling
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
* is guaranteed to be a sorted map, so iterating over it will return fields
* in order by field number.
*/
Map<Descriptors.FieldDescriptor, Object> getAllFields();
/**
* Returns true if the given field is set. This is exactly equivalent to
* calling the generated "has" accessor method corresponding to the field.
* @throws IllegalArgumentException The field is a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
boolean hasField(Descriptors.FieldDescriptor field);
/**
* Obtains the value of the given field, or the default value if it is
* not set. For primitive fields, the boxed primitive value is returned.
* For enum fields, the EnumValueDescriptor for the value is returend. For
* embedded message fields, the sub-message is returned. For repeated
* fields, a java.util.List is returned.
*/
Object getField(Descriptors.FieldDescriptor field);
/**
* Gets the number of elements of a repeated field. This is exactly
* equivalent to calling the generated "Count" accessor method corresponding
* to the field.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
/**
* Gets an element of a repeated field. For primitive fields, the boxed
* primitive value is returned. For enum fields, the EnumValueDescriptor
* for the value is returend. For embedded message fields, the sub-message
* is returned.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
/** Get the {@link UnknownFieldSet} for this message. */
UnknownFieldSet getUnknownFields();
// -----------------------------------------------------------------
// Comparison and hashing
/**
* Compares the specified object with this message for equality. Returns
* <tt>true</tt> if the given object is a message of the same type (as
* defined by {@code getDescriptorForType()}) and has identical values for
* all of its fields.
*
* @param other object to be compared for equality with this message
* @return <tt>true</tt> if the specified object is equal to this message
*/
@Override
boolean equals(Object other);
/**
* Returns the hash code value for this message. The hash code of a message
* is defined to be <tt>getDescriptor().hashCode() ^ map.hashCode()</tt>,
* where <tt>map</tt> is a map of field numbers to field values.
*
* @return the hash code value for this message
* @see Map#hashCode()
*/
@Override
int hashCode();
// -----------------------------------------------------------------
// Convenience methods.
/**
* Converts the message to a string in protocol buffer text format. This is
* just a trivial wrapper around {@link TextFormat#printToString(Message)}.
*/
@Override
String toString();
// =================================================================
// Builders
// (From MessageLite, re-declared here only for return type covariance.)
Builder newBuilderForType();
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
interface Builder extends MessageLite.Builder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder clear();
/**
* Merge {@code other} into the message being built. {@code other} must
* have the exact same type as {@code this} (i.e.
* {@code getDescriptorForType() == other.getDescriptorForType()}).
*
* Merging occurs as follows. For each field:<br>
* * For singular primitive fields, if the field is set in {@code other},
* then {@code other}'s value overwrites the value in this message.<br>
* * For singular message fields, if the field is set in {@code other},
* it is merged into the corresponding sub-message of this message
* using the same merging rules.<br>
* * For repeated fields, the elements in {@code other} are concatenated
* with the elements in this message.
*
* This is equivalent to the {@code Message::MergeFrom} method in C++.
*/
Builder mergeFrom(Message other);
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Message build();
Message buildPartial();
Builder clone();
Builder mergeFrom(CodedInputStream input) throws IOException;
Builder mergeFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Get the message's type's descriptor.
* See {@link Message#getDescriptorForType()}.
*/
Descriptors.Descriptor getDescriptorForType();
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Message getDefaultInstanceForType();
/**
* Like {@link Message#getAllFields()}. The returned map may or may not
* reflect future changes to the builder. Either way, the returned map is
* itself unmodifiable.
*/
Map<Descriptors.FieldDescriptor, Object> getAllFields();
/**
* Create a Builder for messages of the appropriate type for the given
* field. Messages built with this can then be passed to setField(),
* setRepeatedField(), or addRepeatedField().
*/
Builder newBuilderForField(Descriptors.FieldDescriptor field);
/** Like {@link Message#hasField(Descriptors.FieldDescriptor)} */
boolean hasField(Descriptors.FieldDescriptor field);
/** Like {@link Message#getField(Descriptors.FieldDescriptor)} */
Object getField(Descriptors.FieldDescriptor field);
/**
* Sets a field to the given value. The value must be of the correct type
* for this field, i.e. the same type that
* {@link Message#getField(Descriptors.FieldDescriptor)} would return.
*/
Builder setField(Descriptors.FieldDescriptor field, Object value);
/**
* Clears the field. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the field.
*/
Builder clearField(Descriptors.FieldDescriptor field);
/**
* Like {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}
*/
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
/**
* Like {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}
*/
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
/**
* Sets an element of a repeated field to the given value. The value must
* be of the correct type for this field, i.e. the same type that
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
* return.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Builder setRepeatedField(Descriptors.FieldDescriptor field,
int index, Object value);
/**
* Like {@code setRepeatedField}, but appends the value as a new element.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
/** Get the {@link UnknownFieldSet} for this message. */
UnknownFieldSet getUnknownFields();
/** Set the {@link UnknownFieldSet} for this message. */
Builder setUnknownFields(UnknownFieldSet unknownFields);
/**
* Merge some unknown fields into the {@link UnknownFieldSet} for this
* message.
*/
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
// ---------------------------------------------------------------
// Convenience methods.
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
Builder mergeFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(InputStream input) throws IOException;
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
boolean mergeDelimitedFrom(InputStream input)
throws IOException;
boolean mergeDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View file

@ -0,0 +1,335 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
// mergeFrom*() could return BuilderType for better type-safety.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Abstract interface implemented by Protocol Message objects.
*
* <p>This interface is implemented by all protocol message objects. Non-lite
* messages additionally implement the Message interface, which is a subclass
* of MessageLite. Use MessageLite instead when you only need the subset of
* features which it supports -- namely, nothing that uses descriptors or
* reflection. You can instruct the protocol compiler to generate classes
* which implement only MessageLite, not the full Message interface, by adding
* the follow line to the .proto file:
* <pre>
* option optimize_for = LITE_RUNTIME;
* </pre>
*
* <p>This is particularly useful on resource-constrained systems where the
* full protocol buffers runtime library is too big.
*
* <p>Note that on non-constrained systems (e.g. servers) when you need to link
* in lots of protocol definitions, a better way to reduce total code footprint
* is to use {@code optimize_for = CODE_SIZE}. This will make the generated
* code smaller while still supporting all the same features (at the expense of
* speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
* small number of message types linked into your binary, in which case the
* size of the protocol buffers runtime itself is the biggest problem.
*
* @author kenton@google.com Kenton Varda
*/
public interface MessageLite {
/**
* Get an instance of the type with all fields set to their default values.
* This may or may not be a singleton. This differs from the
* {@code getDefaultInstance()} method of generated message classes in that
* this method is an abstract method of the {@code MessageLite} interface
* whereas {@code getDefaultInstance()} is a static method of a specific
* class. They return the same thing.
*/
MessageLite getDefaultInstanceForType();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
boolean isInitialized();
/**
* Serializes the message and writes it to {@code output}. This does not
* flush or close the stream.
*/
void writeTo(CodedOutputStream output) throws IOException;
/**
* Get the number of bytes required to encode this message. The result
* is only computed on the first call and memoized after that.
*/
int getSerializedSize();
// -----------------------------------------------------------------
// Convenience methods.
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
ByteString toByteString();
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
byte[] toByteArray();
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
* not flush or close the stream.
* <p>
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
* any more data to the stream after the message, you must somehow ensure
* that the parser on the receiving end does not interpret this as being
* part of the protocol message. This can be done e.g. by writing the size
* of the message before the data, then making sure to limit the input to
* that size on the receiving end (e.g. by wrapping the InputStream in one
* which limits the input). Alternatively, just use
* {@link #writeDelimitedTo(OutputStream)}.
*/
void writeTo(OutputStream output) throws IOException;
/**
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
* as a varint before writing the data. This allows more data to be written
* to the stream after the message without the need to delimit the message
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
* to parse messages written by this method.
*/
void writeDelimitedTo(OutputStream output) throws IOException;
// =================================================================
// Builders
/**
* Constructs a new builder for a message of the same type as this message.
*/
Builder newBuilderForType();
/**
* Constructs a builder initialized with the current message. Use this to
* derive a new message from the current one.
*/
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
interface Builder extends Cloneable {
/** Resets all fields to their default values. */
Builder clear();
/**
* Construct the final message. Once this is called, the Builder is no
* longer valid, and calling any other method will result in undefined
* behavior and may throw a NullPointerException. If you need to continue
* working with the builder after calling {@code build()}, {@code clone()}
* it first.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
*/
MessageLite build();
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
* Once this is called, the Builder is no longer valid, and calling any
* will result in undefined behavior and may throw a NullPointerException.
*
* If you need to continue working with the builder after calling
* {@code buildPartial()}, {@code clone()} it first.
*/
MessageLite buildPartial();
/**
* Clones the Builder.
* @see Object#clone()
*/
Builder clone();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*/
boolean isInitialized();
/**
* Parses a message of this type from the input and merges it with this
* message, as if using {@link Builder#mergeFrom(MessageLite)}.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
* required fields, it will throw an {@link UninitializedMessageException},
* which is a {@code RuntimeException} and thus might not be caught. There
* are a few good ways to deal with this:
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
* <li>Parse the message separately using one of the static
* {@code parseFrom} methods, then use {@link #mergeFrom(MessageLite)}
* to merge it with this one. {@code parseFrom} will throw an
* {@link InvalidProtocolBufferException} (an {@code IOException})
* if some required fields are missing.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
Builder mergeFrom(CodedInputStream input) throws IOException;
/**
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
* parses extensions. The extensions that you want to be able to parse
* must be registered in {@code extensionRegistry}. Extensions not in
* the registry will be treated as unknown fields.
*/
Builder mergeFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Get the message's type's default instance.
* See {@link MessageLite#getDefaultInstanceForType()}.
*/
MessageLite getDefaultInstanceForType();
// ---------------------------------------------------------------
// Convenience methods.
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
* reads the <i>entire</i> input (unless it throws an exception). If you
* want it to stop earlier, you will need to wrap your input in some
* wrapper stream that limits reading. Or, use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
* and {@link #mergeDelimitedFrom(InputStream)} to read it.
* <p>
* Despite usually reading the entire input, this does not close the stream.
*/
Builder mergeFrom(InputStream input) throws IOException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
*/
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
* Instead, the size of the message (encoded as a varint) is read first,
* then the message data. Use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
* this format.
*
* @returns True if successful, or false if the stream is at EOF when the
* method starts. Any other error (including reaching EOF during
* parsing) will cause an exception to be thrown.
*/
boolean mergeDelimitedFrom(InputStream input)
throws IOException;
/**
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
*/
boolean mergeDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View file

@ -0,0 +1,58 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
/**
* Interface of useful methods added to all enums generated by the protocol
* compiler.
*/
public interface ProtocolMessageEnum extends Internal.EnumLite {
/**
* Return the value's numeric value as defined in the .proto file.
*/
int getNumber();
/**
* Return the value's descriptor, which contains information such as
* value name, number, and type.
*/
EnumValueDescriptor getValueDescriptor();
/**
* Return the enum type's descriptor, which contains information
* about each defined value, etc.
*/
EnumDescriptor getDescriptorForType();
}

View file

@ -0,0 +1,47 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Interface for an RPC callback, normally called when an RPC completes.
* {@code ParameterType} is normally the method's response message type.
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcCallback<ParameterType> {
void run(ParameterType parameter);
}

View file

@ -0,0 +1,71 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
* communication line to a {@link Service} which can be used to call that
* {@link Service}'s methods. The {@link Service} may be running on another
* machine. Normally, you should not call an {@code RpcChannel} directly, but
* instead construct a stub {@link Service} wrapping it. Example:
*
* <pre>
* RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
* RpcController controller = rpcImpl.newController();
* MyService service = MyService.newStub(channel);
* service.myMethod(controller, request, callback);
* </pre>
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcChannel {
/**
* Call the given method of the remote service. This method is similar to
* {@code Service.callMethod()} with one important difference: the caller
* decides the types of the {@code Message} objects, not the callee. The
* request may be of any type as long as
* {@code request.getDescriptor() == method.getInputType()}.
* The response passed to the callback will be of the same type as
* {@code responsePrototype} (which must have
* {@code getDescriptor() == method.getOutputType()}).
*/
void callMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
Message responsePrototype,
RpcCallback<Message> done);
}

View file

@ -0,0 +1,118 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>An {@code RpcController} mediates a single method call. The primary
* purpose of the controller is to provide a way to manipulate settings
* specific to the RPC implementation and to find out about RPC-level errors.
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* <p>The methods provided by the {@code RpcController} interface are intended
* to be a "least common denominator" set of features which we expect all
* implementations to support. Specific implementations may provide more
* advanced features (e.g. deadline propagation).
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcController {
// -----------------------------------------------------------------
// These calls may be made from the client side only. Their results
// are undefined on the server side (may throw RuntimeExceptions).
/**
* Resets the RpcController to its initial state so that it may be reused in
* a new call. This can be called from the client side only. It must not
* be called while an RPC is in progress.
*/
void reset();
/**
* After a call has finished, returns true if the call failed. The possible
* reasons for failure depend on the RPC implementation. {@code failed()}
* most only be called on the client side, and must not be called before a
* call has finished.
*/
boolean failed();
/**
* If {@code failed()} is {@code true}, returns a human-readable description
* of the error.
*/
String errorText();
/**
* Advises the RPC system that the caller desires that the RPC call be
* canceled. The RPC system may cancel it immediately, may wait awhile and
* then cancel it, or may not even cancel the call at all. If the call is
* canceled, the "done" callback will still be called and the RpcController
* will indicate that the call failed at that time.
*/
void startCancel();
// -----------------------------------------------------------------
// These calls may be made from the server side only. Their results
// are undefined on the client side (may throw RuntimeExceptions).
/**
* Causes {@code failed()} to return true on the client side. {@code reason}
* will be incorporated into the message returned by {@code errorText()}.
* If you find you need to return machine-readable information about
* failures, you should incorporate it into your response protocol buffer
* and should NOT call {@code setFailed()}.
*/
void setFailed(String reason);
/**
* If {@code true}, indicates that the client canceled the RPC, so the server
* may as well give up on replying to it. This method must be called on the
* server side only. The server should still call the final "done" callback.
*/
boolean isCanceled();
/**
* Asks that the given callback be called when the RPC is canceled. The
* parameter passed to the callback will always be {@code null}. The
* callback will always be called exactly once. If the RPC completes without
* being canceled, the callback will be called after completion. If the RPC
* has already been canceled when NotifyOnCancel() is called, the callback
* will be called immediately.
*
* <p>{@code notifyOnCancel()} must be called no more than once per request.
* It must be called on the server side only.
*/
void notifyOnCancel(RpcCallback<Object> callback);
}

View file

@ -0,0 +1,135 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Grab-bag of utility functions useful when dealing with RPCs.
*
* @author kenton@google.com Kenton Varda
*/
public final class RpcUtil {
private RpcUtil() {}
/**
* Take an {@code RpcCallback<Message>} and convert it to an
* {@code RpcCallback} accepting a specific message type. This is always
* type-safe (parameter type contravariance).
*/
@SuppressWarnings("unchecked")
public static <Type extends Message> RpcCallback<Type>
specializeCallback(final RpcCallback<Message> originalCallback) {
return (RpcCallback<Type>)originalCallback;
// The above cast works, but only due to technical details of the Java
// implementation. A more theoretically correct -- but less efficient --
// implementation would be as follows:
// return new RpcCallback<Type>() {
// public void run(Type parameter) {
// originalCallback.run(parameter);
// }
// };
}
/**
* Take an {@code RpcCallback} accepting a specific message type and convert
* it to an {@code RpcCallback<Message>}. The generalized callback will
* accept any message object which has the same descriptor, and will convert
* it to the correct class before calling the original callback. However,
* if the generalized callback is given a message with a different descriptor,
* an exception will be thrown.
*/
public static <Type extends Message>
RpcCallback<Message> generalizeCallback(
final RpcCallback<Type> originalCallback,
final Class<Type> originalClass,
final Type defaultInstance) {
return new RpcCallback<Message>() {
public void run(final Message parameter) {
Type typedParameter;
try {
typedParameter = originalClass.cast(parameter);
} catch (ClassCastException ignored) {
typedParameter = copyAsType(defaultInstance, parameter);
}
originalCallback.run(typedParameter);
}
};
}
/**
* Creates a new message of type "Type" which is a copy of "source". "source"
* must have the same descriptor but may be a different class (e.g.
* DynamicMessage).
*/
@SuppressWarnings("unchecked")
private static <Type extends Message> Type copyAsType(
final Type typeDefaultInstance, final Message source) {
return (Type)typeDefaultInstance.newBuilderForType()
.mergeFrom(source)
.build();
}
/**
* Creates a callback which can only be called once. This may be useful for
* security, when passing a callback to untrusted code: most callbacks do
* not expect to be called more than once, so doing so may expose bugs if it
* is not prevented.
*/
public static <ParameterType>
RpcCallback<ParameterType> newOneTimeCallback(
final RpcCallback<ParameterType> originalCallback) {
return new RpcCallback<ParameterType>() {
private boolean alreadyCalled = false;
public void run(final ParameterType parameter) {
synchronized(this) {
if (alreadyCalled) {
throw new AlreadyCalledException();
}
alreadyCalled = true;
}
originalCallback.run(parameter);
}
};
}
/**
* Exception thrown when a one-time callback is called more than once.
*/
public static final class AlreadyCalledException extends RuntimeException {
private static final long serialVersionUID = 5469741279507848266L;
public AlreadyCalledException() {
super("This RpcCallback was already called and cannot be called " +
"multiple times.");
}
}
}

View file

@ -0,0 +1,117 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Abstract base interface for protocol-buffer-based RPC services. Services
* themselves are abstract classes (implemented either by servers or as
* stubs), but they subclass this base interface. The methods of this
* interface can be used to call the methods of the service without knowing
* its exact type at compile time (analogous to the Message interface).
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface Service {
/**
* Get the {@code ServiceDescriptor} describing this service and its methods.
*/
Descriptors.ServiceDescriptor getDescriptorForType();
/**
* <p>Call a method of the service specified by MethodDescriptor. This is
* normally implemented as a simple {@code switch()} that calls the standard
* definitions of the service's methods.
*
* <p>Preconditions:
* <ul>
* <li>{@code method.getService() == getDescriptorForType()}
* <li>{@code request} is of the exact same class as the object returned by
* {@code getRequestPrototype(method)}.
* <li>{@code controller} is of the correct type for the RPC implementation
* being used by this Service. For stubs, the "correct type" depends
* on the RpcChannel which the stub is using. Server-side Service
* implementations are expected to accept whatever type of
* {@code RpcController} the server-side RPC implementation uses.
* </ul>
*
* <p>Postconditions:
* <ul>
* <li>{@code done} will be called when the method is complete. This may be
* before {@code callMethod()} returns or it may be at some point in
* the future.
* <li>The parameter to {@code done} is the response. It must be of the
* exact same type as would be returned by
* {@code getResponsePrototype(method)}.
* <li>If the RPC failed, the parameter to {@code done} will be
* {@code null}. Further details about the failure can be found by
* querying {@code controller}.
* </ul>
*/
void callMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
RpcCallback<Message> done);
/**
* <p>{@code callMethod()} requires that the request passed in is of a
* particular subclass of {@code Message}. {@code getRequestPrototype()}
* gets the default instances of this type for a given method. You can then
* call {@code Message.newBuilderForType()} on this instance to
* construct a builder to build an object which you can then pass to
* {@code callMethod()}.
*
* <p>Example:
* <pre>
* MethodDescriptor method =
* service.getDescriptorForType().findMethodByName("Foo");
* Message request =
* stub.getRequestPrototype(method).newBuilderForType()
* .mergeFrom(input).build();
* service.callMethod(method, request, callback);
* </pre>
*/
Message getRequestPrototype(Descriptors.MethodDescriptor method);
/**
* Like {@code getRequestPrototype()}, but gets a prototype of the response
* message. {@code getResponsePrototype()} is generally not needed because
* the {@code Service} implementation constructs the response message itself,
* but it may be useful in some cases to know ahead of time what type of
* object will be returned.
*/
Message getResponsePrototype(Descriptors.MethodDescriptor method);
}

View file

@ -0,0 +1,44 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Thrown by blocking RPC methods when a failure occurs.
*
* @author cpovirk@google.com (Chris Povirk)
*/
public final class ServiceException extends Exception {
private static final long serialVersionUID = -1219262335729891920L;
public ServiceException(final String message) {
super(message);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,99 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.Collections;
import java.util.List;
/**
* Thrown when attempting to build a protocol message that is missing required
* fields. This is a {@code RuntimeException} because it normally represents
* a programming error: it happens when some code which constructs a message
* fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
* throw this; they throw an {@link InvalidProtocolBufferException} if
* required fields are missing, because it is not a programming error to
* receive an incomplete message. In other words,
* {@code UninitializedMessageException} should never be thrown by correct
* code, but {@code InvalidProtocolBufferException} might be.
*
* @author kenton@google.com Kenton Varda
*/
public class UninitializedMessageException extends RuntimeException {
private static final long serialVersionUID = -7466929953374883507L;
public UninitializedMessageException(final MessageLite message) {
super("Message was missing required fields. (Lite runtime could not " +
"determine which fields were missing).");
missingFields = null;
}
public UninitializedMessageException(final List<String> missingFields) {
super(buildDescription(missingFields));
this.missingFields = missingFields;
}
private final List<String> missingFields;
/**
* Get a list of human-readable names of required fields missing from this
* message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
* Returns null if the lite runtime was used, since it lacks the ability to
* find missing fields.
*/
public List<String> getMissingFields() {
return Collections.unmodifiableList(missingFields);
}
/**
* Converts this exception to an {@link InvalidProtocolBufferException}.
* When a parsed message is missing required fields, this should be thrown
* instead of {@code UninitializedMessageException}.
*/
public InvalidProtocolBufferException asInvalidProtocolBufferException() {
return new InvalidProtocolBufferException(getMessage());
}
/** Construct the description string for this exception. */
private static String buildDescription(final List<String> missingFields) {
final StringBuilder description =
new StringBuilder("Message missing required fields: ");
boolean first = true;
for (final String field : missingFields) {
if (first) {
first = false;
} else {
description.append(", ");
}
description.append(field);
}
return description.toString();
}
}

View file

@ -0,0 +1,953 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* {@code UnknownFieldSet} is used to keep track of fields which were seen when
* parsing a protocol message but whose field numbers or types are unrecognized.
* This most frequently occurs when new fields are added to a message type
* and then messages containing those feilds are read by old software that was
* compiled before the new types were added.
*
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
* {@link Message.Builder} contains an {@link Builder}).
*
* <p>Most users will never need to use this class.
*
* @author kenton@google.com Kenton Varda
*/
public final class UnknownFieldSet implements MessageLite {
private UnknownFieldSet() {}
/** Create a new {@link Builder}. */
public static Builder newBuilder() {
return Builder.create();
}
/**
* Create a new {@link Builder} and initialize it to be a copy
* of {@code copyFrom}.
*/
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code UnknownFieldSet}. */
public static UnknownFieldSet getDefaultInstance() {
return defaultInstance;
}
public UnknownFieldSet getDefaultInstanceForType() {
return defaultInstance;
}
private static final UnknownFieldSet defaultInstance =
new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
/**
* Construct an {@code UnknownFieldSet} around the given map. The map is
* expected to be immutable.
*/
private UnknownFieldSet(final Map<Integer, Field> fields) {
this.fields = fields;
}
private Map<Integer, Field> fields;
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
return (other instanceof UnknownFieldSet) &&
fields.equals(((UnknownFieldSet) other).fields);
}
@Override
public int hashCode() {
return fields.hashCode();
}
/** Get a map of fields in the set by number. */
public Map<Integer, Field> asMap() {
return fields;
}
/** Check if the given field number is present in the set. */
public boolean hasField(final int number) {
return fields.containsKey(number);
}
/**
* Get a field by number. Returns an empty field if not present. Never
* returns {@code null}.
*/
public Field getField(final int number) {
final Field result = fields.get(number);
return (result == null) ? Field.getDefaultInstance() : result;
}
/** Serializes the set and writes it to {@code output}. */
public void writeTo(final CodedOutputStream output) throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeTo(entry.getKey(), output);
}
}
/**
* Converts the set to a string in protocol buffer text format. This is
* just a trivial wrapper around
* {@link TextFormat#printToString(UnknownFieldSet)}.
*/
@Override
public String toString() {
return TextFormat.printToString(this);
}
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public void writeTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
writeTo(codedOutput);
codedOutput.flush();
}
/** Get the number of bytes required to encode this set. */
public int getSerializedSize() {
int result = 0;
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSize(entry.getKey());
}
return result;
}
/**
* Serializes the set and writes it to {@code output} using
* {@code MessageSet} wire format.
*/
public void writeAsMessageSetTo(final CodedOutputStream output)
throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeAsMessageSetExtensionTo(
entry.getKey(), output);
}
}
/**
* Get the number of bytes required to encode this set using
* {@code MessageSet} wire format.
*/
public int getSerializedSizeAsMessageSet() {
int result = 0;
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
entry.getKey());
}
return result;
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
/** Parse an {@code UnknownFieldSet} from the given input stream. */
public static UnknownFieldSet parseFrom(final CodedInputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(final ByteString data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(final byte[] data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
public static UnknownFieldSet parseFrom(final InputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
public Builder newBuilderForType() {
return newBuilder();
}
public Builder toBuilder() {
return newBuilder().mergeFrom(this);
}
/**
* Builder for {@link UnknownFieldSet}s.
*
* <p>Note that this class maintains {@link Field.Builder}s for all fields
* in the set. Thus, adding one element to an existing {@link Field} does not
* require making a copy. This is important for efficient parsing of
* unknown repeated fields. However, it implies that {@link Field}s cannot
* be constructed independently, nor can two {@link UnknownFieldSet}s share
* the same {@code Field} object.
*
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder implements MessageLite.Builder {
// This constructor should never be called directly (except from 'create').
private Builder() {}
private Map<Integer, Field> fields;
// Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a
// row (important when parsing an unknown repeated field).
private int lastFieldNumber;
private Field.Builder lastField;
private static Builder create() {
Builder builder = new Builder();
builder.reinitialize();
return builder;
}
/**
* Get a field builder for the given field number which includes any
* values that already exist.
*/
private Field.Builder getFieldBuilder(final int number) {
if (lastField != null) {
if (number == lastFieldNumber) {
return lastField;
}
// Note: addField() will reset lastField and lastFieldNumber.
addField(lastFieldNumber, lastField.build());
}
if (number == 0) {
return null;
} else {
final Field existing = fields.get(number);
lastFieldNumber = number;
lastField = Field.newBuilder();
if (existing != null) {
lastField.mergeFrom(existing);
}
return lastField;
}
}
/**
* Build the {@link UnknownFieldSet} and return it.
*
* <p>Once {@code build()} has been called, the {@code Builder} will no
* longer be usable. Calling any method after {@code build()} will result
* in undefined behavior and can cause a {@code NullPointerException} to be
* thrown.
*/
public UnknownFieldSet build() {
getFieldBuilder(0); // Force lastField to be built.
final UnknownFieldSet result;
if (fields.isEmpty()) {
result = getDefaultInstance();
} else {
result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
}
fields = null;
return result;
}
public UnknownFieldSet buildPartial() {
// No required fields, so this is the same as build().
return build();
}
@Override
public Builder clone() {
getFieldBuilder(0); // Force lastField to be built.
return UnknownFieldSet.newBuilder().mergeFrom(
new UnknownFieldSet(fields));
}
public UnknownFieldSet getDefaultInstanceForType() {
return UnknownFieldSet.getDefaultInstance();
}
private void reinitialize() {
fields = Collections.emptyMap();
lastFieldNumber = 0;
lastField = null;
}
/** Reset the builder to an empty set. */
public Builder clear() {
reinitialize();
return this;
}
/**
* Merge the fields from {@code other} into this set. If a field number
* exists in both sets, {@code other}'s values for that field will be
* appended to the values in this set.
*/
public Builder mergeFrom(final UnknownFieldSet other) {
if (other != getDefaultInstance()) {
for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
mergeField(entry.getKey(), entry.getValue());
}
}
return this;
}
/**
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, the two are merged.
*/
public Builder mergeField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
if (hasField(number)) {
getFieldBuilder(number).mergeFrom(field);
} else {
// Optimization: We could call getFieldBuilder(number).mergeFrom(field)
// in this case, but that would create a copy of the Field object.
// We'd rather reuse the one passed to us, so call addField() instead.
addField(number, field);
}
return this;
}
/**
* Convenience method for merging a new field containing a single varint
* value. This is used in particular when an unknown enum value is
* encountered.
*/
public Builder mergeVarintField(final int number, final int value) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
getFieldBuilder(number).addVarint(value);
return this;
}
/** Check if the given field number is present in the set. */
public boolean hasField(final int number) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
return number == lastFieldNumber || fields.containsKey(number);
}
/**
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, it is removed.
*/
public Builder addField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
if (lastField != null && lastFieldNumber == number) {
// Discard this.
lastField = null;
lastFieldNumber = 0;
}
if (fields.isEmpty()) {
fields = new TreeMap<Integer,Field>();
}
fields.put(number, field);
return this;
}
/**
* Get all present {@code Field}s as an immutable {@code Map}. If more
* fields are added, the changes may or may not be reflected in this map.
*/
public Map<Integer, Field> asMap() {
getFieldBuilder(0); // Force lastField to be built.
return Collections.unmodifiableMap(fields);
}
/**
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
public Builder mergeFrom(final CodedInputStream input) throws IOException {
while (true) {
final int tag = input.readTag();
if (tag == 0 || !mergeFieldFrom(tag, input)) {
break;
}
}
return this;
}
/**
* Parse a single field from {@code input} and merge it into this set.
* @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an engroup tag.
*/
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
throws IOException {
final int number = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
getFieldBuilder(number).addVarint(input.readInt64());
return true;
case WireFormat.WIRETYPE_FIXED64:
getFieldBuilder(number).addFixed64(input.readFixed64());
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
getFieldBuilder(number).addLengthDelimited(input.readBytes());
return true;
case WireFormat.WIRETYPE_START_GROUP:
final Builder subBuilder = newBuilder();
input.readGroup(number, subBuilder,
ExtensionRegistry.getEmptyRegistry());
getFieldBuilder(number).addGroup(subBuilder.build());
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
getFieldBuilder(number).addFixed32(input.readFixed32());
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
/**
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = CodedInputStream.newInstance(data);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
/**
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return this;
}
public boolean mergeDelimitedFrom(InputStream input)
throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
}
final int size = CodedInputStream.readRawVarint32(firstByte, input);
final InputStream limitedInput = new LimitedInputStream(input, size);
mergeFrom(limitedInput);
return true;
}
public boolean mergeDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeDelimitedFrom(input);
}
public Builder mergeFrom(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public Builder mergeFrom(
ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public Builder mergeFrom(
byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(
byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data, off, len);
}
public Builder mergeFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
}
/**
* Represents a single field in an {@code UnknownFieldSet}.
*
* <p>A {@code Field} consists of five lists of values. The lists correspond
* to the five "wire types" used in the protocol buffer binary format.
* The wire type of each field can be determined from the encoded form alone,
* without knowing the field's declared type. So, we are able to parse
* unknown values at least this far and separate them. Normally, only one
* of the five lists will contain any values, since it is impossible to
* define a valid message type that declares two different types for the
* same field number. However, the code is designed to allow for the case
* where the same unknown field number is encountered using multiple different
* wire types.
*
* <p>{@code Field} is an immutable class. To construct one, you must use a
* {@link Builder}.
*
* @see UnknownFieldSet
*/
public static final class Field {
private Field() {}
/** Construct a new {@link Builder}. */
public static Builder newBuilder() {
return Builder.create();
}
/**
* Construct a new {@link Builder} and initialize it to a copy of
* {@code copyFrom}.
*/
public static Builder newBuilder(final Field copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code Field}. */
public static Field getDefaultInstance() {
return fieldDefaultInstance;
}
private static final Field fieldDefaultInstance = newBuilder().build();
/** Get the list of varint values for this field. */
public List<Long> getVarintList() { return varint; }
/** Get the list of fixed32 values for this field. */
public List<Integer> getFixed32List() { return fixed32; }
/** Get the list of fixed64 values for this field. */
public List<Long> getFixed64List() { return fixed64; }
/** Get the list of length-delimited values for this field. */
public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
/**
* Get the list of embedded group values for this field. These are
* represented using {@link UnknownFieldSet}s rather than {@link Message}s
* since the group's type is presumably unknown.
*/
public List<UnknownFieldSet> getGroupList() { return group; }
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Field)) {
return false;
}
return Arrays.equals(getIdentityArray(),
((Field) other).getIdentityArray());
}
@Override
public int hashCode() {
return Arrays.hashCode(getIdentityArray());
}
/**
* Returns the array of objects to be used to uniquely identify this
* {@link Field} instance.
*/
private Object[] getIdentityArray() {
return new Object[] {
varint,
fixed32,
fixed64,
lengthDelimited,
group};
}
/**
* Serializes the field, including field number, and writes it to
* {@code output}.
*/
public void writeTo(final int fieldNumber, final CodedOutputStream output)
throws IOException {
for (final long value : varint) {
output.writeUInt64(fieldNumber, value);
}
for (final int value : fixed32) {
output.writeFixed32(fieldNumber, value);
}
for (final long value : fixed64) {
output.writeFixed64(fieldNumber, value);
}
for (final ByteString value : lengthDelimited) {
output.writeBytes(fieldNumber, value);
}
for (final UnknownFieldSet value : group) {
output.writeGroup(fieldNumber, value);
}
}
/**
* Get the number of bytes required to encode this field, including field
* number.
*/
public int getSerializedSize(final int fieldNumber) {
int result = 0;
for (final long value : varint) {
result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
}
for (final int value : fixed32) {
result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
}
for (final long value : fixed64) {
result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
}
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeBytesSize(fieldNumber, value);
}
for (final UnknownFieldSet value : group) {
result += CodedOutputStream.computeGroupSize(fieldNumber, value);
}
return result;
}
/**
* Serializes the field, including field number, and writes it to
* {@code output}, using {@code MessageSet} wire format.
*/
public void writeAsMessageSetExtensionTo(
final int fieldNumber,
final CodedOutputStream output)
throws IOException {
for (final ByteString value : lengthDelimited) {
output.writeRawMessageSetExtension(fieldNumber, value);
}
}
/**
* Get the number of bytes required to encode this field, including field
* number, using {@code MessageSet} wire format.
*/
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
int result = 0;
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeRawMessageSetExtensionSize(
fieldNumber, value);
}
return result;
}
private List<Long> varint;
private List<Integer> fixed32;
private List<Long> fixed64;
private List<ByteString> lengthDelimited;
private List<UnknownFieldSet> group;
/**
* Used to build a {@link Field} within an {@link UnknownFieldSet}.
*
* <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder {
// This constructor should never be called directly (except from 'create').
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new Field();
return builder;
}
private Field result;
/**
* Build the field. After {@code build()} has been called, the
* {@code Builder} is no longer usable. Calling any other method will
* result in undefined behavior and can cause a
* {@code NullPointerException} to be thrown.
*/
public Field build() {
if (result.varint == null) {
result.varint = Collections.emptyList();
} else {
result.varint = Collections.unmodifiableList(result.varint);
}
if (result.fixed32 == null) {
result.fixed32 = Collections.emptyList();
} else {
result.fixed32 = Collections.unmodifiableList(result.fixed32);
}
if (result.fixed64 == null) {
result.fixed64 = Collections.emptyList();
} else {
result.fixed64 = Collections.unmodifiableList(result.fixed64);
}
if (result.lengthDelimited == null) {
result.lengthDelimited = Collections.emptyList();
} else {
result.lengthDelimited =
Collections.unmodifiableList(result.lengthDelimited);
}
if (result.group == null) {
result.group = Collections.emptyList();
} else {
result.group = Collections.unmodifiableList(result.group);
}
final Field returnMe = result;
result = null;
return returnMe;
}
/** Discard the field's contents. */
public Builder clear() {
result = new Field();
return this;
}
/**
* Merge the values in {@code other} into this field. For each list
* of values, {@code other}'s values are append to the ones in this
* field.
*/
public Builder mergeFrom(final Field other) {
if (!other.varint.isEmpty()) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
}
result.varint.addAll(other.varint);
}
if (!other.fixed32.isEmpty()) {
if (result.fixed32 == null) {
result.fixed32 = new ArrayList<Integer>();
}
result.fixed32.addAll(other.fixed32);
}
if (!other.fixed64.isEmpty()) {
if (result.fixed64 == null) {
result.fixed64 = new ArrayList<Long>();
}
result.fixed64.addAll(other.fixed64);
}
if (!other.lengthDelimited.isEmpty()) {
if (result.lengthDelimited == null) {
result.lengthDelimited = new ArrayList<ByteString>();
}
result.lengthDelimited.addAll(other.lengthDelimited);
}
if (!other.group.isEmpty()) {
if (result.group == null) {
result.group = new ArrayList<UnknownFieldSet>();
}
result.group.addAll(other.group);
}
return this;
}
/** Add a varint value. */
public Builder addVarint(final long value) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
}
result.varint.add(value);
return this;
}
/** Add a fixed32 value. */
public Builder addFixed32(final int value) {
if (result.fixed32 == null) {
result.fixed32 = new ArrayList<Integer>();
}
result.fixed32.add(value);
return this;
}
/** Add a fixed64 value. */
public Builder addFixed64(final long value) {
if (result.fixed64 == null) {
result.fixed64 = new ArrayList<Long>();
}
result.fixed64.add(value);
return this;
}
/** Add a length-delimited value. */
public Builder addLengthDelimited(final ByteString value) {
if (result.lengthDelimited == null) {
result.lengthDelimited = new ArrayList<ByteString>();
}
result.lengthDelimited.add(value);
return this;
}
/** Add an embedded group. */
public Builder addGroup(final UnknownFieldSet value) {
if (result.group == null) {
result.group = new ArrayList<UnknownFieldSet>();
}
result.group.add(value);
return this;
}
}
}
}

View file

@ -0,0 +1,163 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* This class is used internally by the Protocol Buffer library and generated
* message implementations. It is public only because those generated messages
* do not reside in the {@code protobuf} package. Others should not use this
* class directly.
*
* This class contains constants and helper functions useful for dealing with
* the Protocol Buffer wire format.
*
* @author kenton@google.com Kenton Varda
*/
public final class WireFormat {
// Do not allow instantiation.
private WireFormat() {}
static final int WIRETYPE_VARINT = 0;
static final int WIRETYPE_FIXED64 = 1;
static final int WIRETYPE_LENGTH_DELIMITED = 2;
static final int WIRETYPE_START_GROUP = 3;
static final int WIRETYPE_END_GROUP = 4;
static final int WIRETYPE_FIXED32 = 5;
static final int TAG_TYPE_BITS = 3;
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
/** Given a tag value, determines the wire type (the lower 3 bits). */
static int getTagWireType(final int tag) {
return tag & TAG_TYPE_MASK;
}
/** Given a tag value, determines the field number (the upper 29 bits). */
public static int getTagFieldNumber(final int tag) {
return tag >>> TAG_TYPE_BITS;
}
/** Makes a tag value given a field number and wire type. */
static int makeTag(final int fieldNumber, final int wireType) {
return (fieldNumber << TAG_TYPE_BITS) | wireType;
}
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum JavaType {
INT(0),
LONG(0L),
FLOAT(0F),
DOUBLE(0D),
BOOLEAN(false),
STRING(""),
BYTE_STRING(ByteString.EMPTY),
ENUM(null),
MESSAGE(null);
JavaType(final Object defaultDefault) {
this.defaultDefault = defaultDefault;
}
/**
* The default default value for fields of this type, if it's a primitive
* type.
*/
Object getDefaultDefault() {
return defaultDefault;
}
private final Object defaultDefault;
}
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum FieldType {
DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
INT64 (JavaType.LONG , WIRETYPE_VARINT ),
UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
INT32 (JavaType.INT , WIRETYPE_VARINT ),
FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) {
public boolean isPackable() { return false; }
},
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
SINT32 (JavaType.INT , WIRETYPE_VARINT ),
SINT64 (JavaType.LONG , WIRETYPE_VARINT );
FieldType(final JavaType javaType, final int wireType) {
this.javaType = javaType;
this.wireType = wireType;
}
private final JavaType javaType;
private final int wireType;
public JavaType getJavaType() { return javaType; }
public int getWireType() { return wireType; }
public boolean isPackable() { return true; }
}
// Field numbers for feilds in MessageSet wire format.
static final int MESSAGE_SET_ITEM = 1;
static final int MESSAGE_SET_TYPE_ID = 2;
static final int MESSAGE_SET_MESSAGE = 3;
// Tag numbers.
static final int MESSAGE_SET_ITEM_TAG =
makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
static final int MESSAGE_SET_ITEM_END_TAG =
makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
static final int MESSAGE_SET_TYPE_ID_TAG =
makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
static final int MESSAGE_SET_MESSAGE_TAG =
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
}

View file

@ -0,0 +1,122 @@
package crosby.binary;
import java.util.Date;
import java.util.List;
import com.google.protobuf.InvalidProtocolBufferException;
import crosby.binary.Osmformat;
import crosby.binary.file.BlockReaderAdapter;
import crosby.binary.file.FileBlock;
import crosby.binary.file.FileBlockPosition;
public abstract class BinaryParser implements BlockReaderAdapter {
protected int granularity;
private long lat_offset;
private long lon_offset;
protected int date_granularity;
private String strings[];
/** Take a Info protocol buffer containing a date and convert it into a java Date object */
protected Date getDate(Osmformat.Info info) {
if (info.hasTimestamp()) {
return new Date(date_granularity * (long) info.getTimestamp());
} else
return NODATE;
}
public static final Date NODATE = new Date();
/** Get a string based on the index used.
*
* Index 0 is reserved to use as a delimiter, therefore, index 1 corresponds to the first string in the table
* @param id
* @return
*/
protected String getStringById(int id) {
return strings[id];
}
@Override
public void handleBlock(FileBlock message) {
// TODO Auto-generated method stub
try {
if (message.getType().equals("OSMHeader")) {
Osmformat.HeaderBlock headerblock = Osmformat.HeaderBlock
.parseFrom(message.getData());
parse(headerblock);
} else if (message.getType().equals("OSMData")) {
Osmformat.PrimitiveBlock primblock = Osmformat.PrimitiveBlock
.parseFrom(message.getData());
parse(primblock);
}
} catch (InvalidProtocolBufferException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new Error("ParseError"); // TODO
}
}
@Override
public boolean skipBlock(FileBlockPosition block) {
// System.out.println("Seeing block of type: "+block.getType());
if (block.getType().equals("OSMData"))
return false;
if (block.getType().equals("OSMHeader"))
return false;
System.out.println("Skipped block of type: " + block.getType());
return true;
}
/** Convert a latitude value stored in a protobuf into a double, compensating for granularity and latitude offset */
public double parseLat(long degree) {
// Support non-zero offsets. (We don't currently generate them)
return (granularity * degree + lat_offset) * .000000001;
}
/** Convert a longitude value stored in a protobuf into a double, compensating for granularity and longitude offset */
public double parseLon(long degree) {
// Support non-zero offsets. (We don't currently generate them)
return (granularity * degree + lon_offset) * .000000001;
}
/** Parse a Primitive block (containing a string table, other paramaters, and PrimitiveGroups */
public void parse(Osmformat.PrimitiveBlock block) {
Osmformat.StringTable stablemessage = block.getStringtable();
strings = new String[stablemessage.getSCount()];
for (int i = 0; i < strings.length; i++) {
strings[i] = stablemessage.getS(i).toStringUtf8();
}
granularity = block.getGranularity();
lat_offset = block.getLatOffset();
lon_offset = block.getLonOffset();
date_granularity = block.getDateGranularity();
for (Osmformat.PrimitiveGroup groupmessage : block
.getPrimitivegroupList()) {
// Exactly one of these should trigger on each loop.
parseNodes(groupmessage.getNodesList());
parseWays(groupmessage.getWaysList());
parseRelations(groupmessage.getRelationsList());
if (groupmessage.hasDense())
parseDense(groupmessage.getDense());
}
}
/** Parse a list of Relation protocol buffers and send the resulting relations to a sink. */
protected abstract void parseRelations(List<Osmformat.Relation> rels);
/** Parse a DenseNode protocol buffer and send the resulting nodes to a sink. */
protected abstract void parseDense(Osmformat.DenseNodes nodes);
/** Parse a list of Node protocol buffers and send the resulting nodes to a sink. */
protected abstract void parseNodes(List<Osmformat.Node> nodes);
/** Parse a list of Way protocol buffers and send the resulting ways to a sink. */
protected abstract void parseWays(List<Osmformat.Way> ways);
/** Parse a header message. */
protected abstract void parse(Osmformat.HeaderBlock header);
}

View file

@ -0,0 +1,148 @@
package crosby.binary;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import crosby.binary.Osmformat.PrimitiveGroup;
import crosby.binary.file.BlockOutputStream;
import crosby.binary.file.FileBlock;
/**
* Generic serializer common code
*
* Serialize a set of blobs and process them. Subclasses implement handlers for
* different API's (osmosis, mkgmap, splitter, etc.)
*
* All data is converted into PrimGroupWriterInterface objects, which are then
* ordered to process their data at the appropriate time.
* */
public class BinarySerializer {
/**
* Interface used to write a group of primitives. One of these for each
* group type (Node, Way, Relation, DenseNode, Changeset)
*/
protected interface PrimGroupWriterInterface {
/** This callback is invoked on each group that is going into the fileblock in order to give it a chance to
* add to the stringtable pool of strings. */
public void addStringsToStringtable();
/**
* This callback is invoked to request that the primgroup serialize itself into the given protocol buffer object.
*/
public Osmformat.PrimitiveGroup serialize();
}
/** Set the granularity (precision of lat/lon, measured in unites of nanodegrees. */
public void configGranularity(int granularity) {
this.granularity = granularity;
}
/** Set whether metadata is to be omitted */
public void configOmit(boolean omit_metadata) {
this.omit_metadata = omit_metadata;
}
/** Configure the maximum number of entities in a batch */
public void configBatchLimit(int batch_limit) {
this.batch_limit = batch_limit;
}
// Paramaters affecting the output size.
protected final int MIN_DENSE = 10;
protected int batch_limit = 4000;
// Parmaters affecting the output.
protected int granularity = 100;
protected int date_granularity = 1000;
protected boolean omit_metadata = false;
/** How many primitives have been seen in this batch */
protected int batch_size = 0;
protected int total_entities = 0;
private StringTable stringtable = new StringTable();
protected List<PrimGroupWriterInterface> groups = new ArrayList<PrimGroupWriterInterface>();
protected BlockOutputStream output;
public BinarySerializer(BlockOutputStream output) {
this.output = output;
}
public StringTable getStringTable() {
return stringtable;
}
public void flush() throws IOException {
processBatch();
output.flush();
}
public void close() throws IOException {
flush();
output.close();
}
long debug_bytes = 0;
public void processBatch() {
// System.out.format("Batch of %d groups: ",groups.size());
if (groups.size() == 0)
return;
Osmformat.PrimitiveBlock.Builder primblock = Osmformat.PrimitiveBlock
.newBuilder();
stringtable.clear();
// Preprocessing: Figure out the stringtable.
for (PrimGroupWriterInterface i : groups)
i.addStringsToStringtable();
stringtable.finish();
// Now, start serializing.
for (PrimGroupWriterInterface i : groups) {
PrimitiveGroup group = i.serialize();
if (group != null)
primblock.addPrimitivegroup(group);
}
primblock.setStringtable(stringtable.serialize());
primblock.setGranularity(this.granularity);
primblock.setDateGranularity(this.date_granularity);
// Only generate data with offset (0,0)
//
Osmformat.PrimitiveBlock message = primblock.build();
// System.out.println(message);
debug_bytes += message.getSerializedSize();
if (false) // TODO: Prettyprinted output.
System.out.format(" =======> %.2f / %.2f (%dk)\n", message
.getSerializedSize() / 1024.0, debug_bytes / 1024 / 1024.0,
total_entities / 1000);
// if (message.getSerializedSize() > 1000000)
// System.out.println(message);
try {
output.write(FileBlock.newInstance("OSMData", message
.toByteString(), null));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new Error(e);
} finally {
batch_size = 0;
groups.clear();
}
// System.out.format("\n");
}
/** Convert from a degrees represented as a double into the serialized offset in nanodegrees.. */
public long mapRawDegrees(double degrees) {
return (long) ((degrees / .000000001));
}
/** Convert from a degrees represented as a double into the serialized offset. */
public int mapDegrees(double degrees) {
return (int) ((degrees / .0000001) / (granularity / 100));
}
}

View file

@ -0,0 +1,891 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: fileformat.proto
package crosby.binary;
public final class Fileformat {
private Fileformat() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
}
public static final class Blob extends
com.google.protobuf.GeneratedMessage {
// Use Blob.newBuilder() to construct.
private Blob() {
initFields();
}
private Blob(boolean noInit) {}
private static final Blob defaultInstance;
public static Blob getDefaultInstance() {
return defaultInstance;
}
public Blob getDefaultInstanceForType() {
return defaultInstance;
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return crosby.binary.Fileformat.internal_static_Blob_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return crosby.binary.Fileformat.internal_static_Blob_fieldAccessorTable;
}
// optional bytes raw = 1;
public static final int RAW_FIELD_NUMBER = 1;
private boolean hasRaw;
private com.google.protobuf.ByteString raw_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasRaw() { return hasRaw; }
public com.google.protobuf.ByteString getRaw() { return raw_; }
// optional int32 raw_size = 2;
public static final int RAW_SIZE_FIELD_NUMBER = 2;
private boolean hasRawSize;
private int rawSize_ = 0;
public boolean hasRawSize() { return hasRawSize; }
public int getRawSize() { return rawSize_; }
// optional bytes zlib_data = 3;
public static final int ZLIB_DATA_FIELD_NUMBER = 3;
private boolean hasZlibData;
private com.google.protobuf.ByteString zlibData_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasZlibData() { return hasZlibData; }
public com.google.protobuf.ByteString getZlibData() { return zlibData_; }
// optional bytes lzma_data = 4;
public static final int LZMA_DATA_FIELD_NUMBER = 4;
private boolean hasLzmaData;
private com.google.protobuf.ByteString lzmaData_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasLzmaData() { return hasLzmaData; }
public com.google.protobuf.ByteString getLzmaData() { return lzmaData_; }
// optional bytes bzip2_data = 5;
public static final int BZIP2_DATA_FIELD_NUMBER = 5;
private boolean hasBzip2Data;
private com.google.protobuf.ByteString bzip2Data_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasBzip2Data() { return hasBzip2Data; }
public com.google.protobuf.ByteString getBzip2Data() { return bzip2Data_; }
private void initFields() {
}
public final boolean isInitialized() {
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
if (hasRaw()) {
output.writeBytes(1, getRaw());
}
if (hasRawSize()) {
output.writeInt32(2, getRawSize());
}
if (hasZlibData()) {
output.writeBytes(3, getZlibData());
}
if (hasLzmaData()) {
output.writeBytes(4, getLzmaData());
}
if (hasBzip2Data()) {
output.writeBytes(5, getBzip2Data());
}
getUnknownFields().writeTo(output);
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (hasRaw()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, getRaw());
}
if (hasRawSize()) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(2, getRawSize());
}
if (hasZlibData()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(3, getZlibData());
}
if (hasLzmaData()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(4, getLzmaData());
}
if (hasBzip2Data()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(5, getBzip2Data());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
}
public static crosby.binary.Fileformat.Blob parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(java.io.InputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.Blob parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) {
return builder.buildParsed();
} else {
return null;
}
}
public static crosby.binary.Fileformat.Blob parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
return builder.buildParsed();
} else {
return null;
}
}
public static crosby.binary.Fileformat.Blob parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static crosby.binary.Fileformat.Blob parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(crosby.binary.Fileformat.Blob prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> {
private crosby.binary.Fileformat.Blob result;
// Construct using crosby.binary.Fileformat.Blob.newBuilder()
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new crosby.binary.Fileformat.Blob();
return builder;
}
protected crosby.binary.Fileformat.Blob internalGetResult() {
return result;
}
public Builder clear() {
if (result == null) {
throw new IllegalStateException(
"Cannot call clear() after build().");
}
result = new crosby.binary.Fileformat.Blob();
return this;
}
public Builder clone() {
return create().mergeFrom(result);
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return crosby.binary.Fileformat.Blob.getDescriptor();
}
public crosby.binary.Fileformat.Blob getDefaultInstanceForType() {
return crosby.binary.Fileformat.Blob.getDefaultInstance();
}
public boolean isInitialized() {
return result.isInitialized();
}
public crosby.binary.Fileformat.Blob build() {
if (result != null && !isInitialized()) {
throw newUninitializedMessageException(result);
}
return buildPartial();
}
private crosby.binary.Fileformat.Blob buildParsed()
throws com.google.protobuf.InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
result).asInvalidProtocolBufferException();
}
return buildPartial();
}
public crosby.binary.Fileformat.Blob buildPartial() {
if (result == null) {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
crosby.binary.Fileformat.Blob returnMe = result;
result = null;
return returnMe;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof crosby.binary.Fileformat.Blob) {
return mergeFrom((crosby.binary.Fileformat.Blob)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(crosby.binary.Fileformat.Blob other) {
if (other == crosby.binary.Fileformat.Blob.getDefaultInstance()) return this;
if (other.hasRaw()) {
setRaw(other.getRaw());
}
if (other.hasRawSize()) {
setRawSize(other.getRawSize());
}
if (other.hasZlibData()) {
setZlibData(other.getZlibData());
}
if (other.hasLzmaData()) {
setLzmaData(other.getLzmaData());
}
if (other.hasBzip2Data()) {
setBzip2Data(other.getBzip2Data());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder(
this.getUnknownFields());
while (true) {
int tag = input.readTag();
switch (tag) {
case 0:
this.setUnknownFields(unknownFields.build());
return this;
default: {
if (!parseUnknownField(input, unknownFields,
extensionRegistry, tag)) {
this.setUnknownFields(unknownFields.build());
return this;
}
break;
}
case 10: {
setRaw(input.readBytes());
break;
}
case 16: {
setRawSize(input.readInt32());
break;
}
case 26: {
setZlibData(input.readBytes());
break;
}
case 34: {
setLzmaData(input.readBytes());
break;
}
case 42: {
setBzip2Data(input.readBytes());
break;
}
}
}
}
// optional bytes raw = 1;
public boolean hasRaw() {
return result.hasRaw();
}
public com.google.protobuf.ByteString getRaw() {
return result.getRaw();
}
public Builder setRaw(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasRaw = true;
result.raw_ = value;
return this;
}
public Builder clearRaw() {
result.hasRaw = false;
result.raw_ = getDefaultInstance().getRaw();
return this;
}
// optional int32 raw_size = 2;
public boolean hasRawSize() {
return result.hasRawSize();
}
public int getRawSize() {
return result.getRawSize();
}
public Builder setRawSize(int value) {
result.hasRawSize = true;
result.rawSize_ = value;
return this;
}
public Builder clearRawSize() {
result.hasRawSize = false;
result.rawSize_ = 0;
return this;
}
// optional bytes zlib_data = 3;
public boolean hasZlibData() {
return result.hasZlibData();
}
public com.google.protobuf.ByteString getZlibData() {
return result.getZlibData();
}
public Builder setZlibData(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasZlibData = true;
result.zlibData_ = value;
return this;
}
public Builder clearZlibData() {
result.hasZlibData = false;
result.zlibData_ = getDefaultInstance().getZlibData();
return this;
}
// optional bytes lzma_data = 4;
public boolean hasLzmaData() {
return result.hasLzmaData();
}
public com.google.protobuf.ByteString getLzmaData() {
return result.getLzmaData();
}
public Builder setLzmaData(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasLzmaData = true;
result.lzmaData_ = value;
return this;
}
public Builder clearLzmaData() {
result.hasLzmaData = false;
result.lzmaData_ = getDefaultInstance().getLzmaData();
return this;
}
// optional bytes bzip2_data = 5;
public boolean hasBzip2Data() {
return result.hasBzip2Data();
}
public com.google.protobuf.ByteString getBzip2Data() {
return result.getBzip2Data();
}
public Builder setBzip2Data(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasBzip2Data = true;
result.bzip2Data_ = value;
return this;
}
public Builder clearBzip2Data() {
result.hasBzip2Data = false;
result.bzip2Data_ = getDefaultInstance().getBzip2Data();
return this;
}
// @@protoc_insertion_point(builder_scope:Blob)
}
static {
defaultInstance = new Blob(true);
crosby.binary.Fileformat.internalForceInit();
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:Blob)
}
public static final class BlockHeader extends
com.google.protobuf.GeneratedMessage {
// Use BlockHeader.newBuilder() to construct.
private BlockHeader() {
initFields();
}
private BlockHeader(boolean noInit) {}
private static final BlockHeader defaultInstance;
public static BlockHeader getDefaultInstance() {
return defaultInstance;
}
public BlockHeader getDefaultInstanceForType() {
return defaultInstance;
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return crosby.binary.Fileformat.internal_static_BlockHeader_descriptor;
}
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
internalGetFieldAccessorTable() {
return crosby.binary.Fileformat.internal_static_BlockHeader_fieldAccessorTable;
}
// required string type = 1;
public static final int TYPE_FIELD_NUMBER = 1;
private boolean hasType;
private java.lang.String type_ = "";
public boolean hasType() { return hasType; }
public java.lang.String getType() { return type_; }
// optional bytes indexdata = 2;
public static final int INDEXDATA_FIELD_NUMBER = 2;
private boolean hasIndexdata;
private com.google.protobuf.ByteString indexdata_ = com.google.protobuf.ByteString.EMPTY;
public boolean hasIndexdata() { return hasIndexdata; }
public com.google.protobuf.ByteString getIndexdata() { return indexdata_; }
// required int32 datasize = 3;
public static final int DATASIZE_FIELD_NUMBER = 3;
private boolean hasDatasize;
private int datasize_ = 0;
public boolean hasDatasize() { return hasDatasize; }
public int getDatasize() { return datasize_; }
private void initFields() {
}
public final boolean isInitialized() {
if (!hasType) return false;
if (!hasDatasize) return false;
return true;
}
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
getSerializedSize();
if (hasType()) {
output.writeString(1, getType());
}
if (hasIndexdata()) {
output.writeBytes(2, getIndexdata());
}
if (hasDatasize()) {
output.writeInt32(3, getDatasize());
}
getUnknownFields().writeTo(output);
}
private int memoizedSerializedSize = -1;
public int getSerializedSize() {
int size = memoizedSerializedSize;
if (size != -1) return size;
size = 0;
if (hasType()) {
size += com.google.protobuf.CodedOutputStream
.computeStringSize(1, getType());
}
if (hasIndexdata()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(2, getIndexdata());
}
if (hasDatasize()) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(3, getDatasize());
}
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return newBuilder().mergeFrom(data, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(java.io.InputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input)) {
return builder.buildParsed();
} else {
return null;
}
}
public static crosby.binary.Fileformat.BlockHeader parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
Builder builder = newBuilder();
if (builder.mergeDelimitedFrom(input, extensionRegistry)) {
return builder.buildParsed();
} else {
return null;
}
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return newBuilder().mergeFrom(input).buildParsed();
}
public static crosby.binary.Fileformat.BlockHeader parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return newBuilder().mergeFrom(input, extensionRegistry)
.buildParsed();
}
public static Builder newBuilder() { return Builder.create(); }
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder(crosby.binary.Fileformat.BlockHeader prototype) {
return newBuilder().mergeFrom(prototype);
}
public Builder toBuilder() { return newBuilder(this); }
public static final class Builder extends
com.google.protobuf.GeneratedMessage.Builder<Builder> {
private crosby.binary.Fileformat.BlockHeader result;
// Construct using crosby.binary.Fileformat.BlockHeader.newBuilder()
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new crosby.binary.Fileformat.BlockHeader();
return builder;
}
protected crosby.binary.Fileformat.BlockHeader internalGetResult() {
return result;
}
public Builder clear() {
if (result == null) {
throw new IllegalStateException(
"Cannot call clear() after build().");
}
result = new crosby.binary.Fileformat.BlockHeader();
return this;
}
public Builder clone() {
return create().mergeFrom(result);
}
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return crosby.binary.Fileformat.BlockHeader.getDescriptor();
}
public crosby.binary.Fileformat.BlockHeader getDefaultInstanceForType() {
return crosby.binary.Fileformat.BlockHeader.getDefaultInstance();
}
public boolean isInitialized() {
return result.isInitialized();
}
public crosby.binary.Fileformat.BlockHeader build() {
if (result != null && !isInitialized()) {
throw newUninitializedMessageException(result);
}
return buildPartial();
}
private crosby.binary.Fileformat.BlockHeader buildParsed()
throws com.google.protobuf.InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
result).asInvalidProtocolBufferException();
}
return buildPartial();
}
public crosby.binary.Fileformat.BlockHeader buildPartial() {
if (result == null) {
throw new IllegalStateException(
"build() has already been called on this Builder.");
}
crosby.binary.Fileformat.BlockHeader returnMe = result;
result = null;
return returnMe;
}
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof crosby.binary.Fileformat.BlockHeader) {
return mergeFrom((crosby.binary.Fileformat.BlockHeader)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(crosby.binary.Fileformat.BlockHeader other) {
if (other == crosby.binary.Fileformat.BlockHeader.getDefaultInstance()) return this;
if (other.hasType()) {
setType(other.getType());
}
if (other.hasIndexdata()) {
setIndexdata(other.getIndexdata());
}
if (other.hasDatasize()) {
setDatasize(other.getDatasize());
}
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder(
this.getUnknownFields());
while (true) {
int tag = input.readTag();
switch (tag) {
case 0:
this.setUnknownFields(unknownFields.build());
return this;
default: {
if (!parseUnknownField(input, unknownFields,
extensionRegistry, tag)) {
this.setUnknownFields(unknownFields.build());
return this;
}
break;
}
case 10: {
setType(input.readString());
break;
}
case 18: {
setIndexdata(input.readBytes());
break;
}
case 24: {
setDatasize(input.readInt32());
break;
}
}
}
}
// required string type = 1;
public boolean hasType() {
return result.hasType();
}
public java.lang.String getType() {
return result.getType();
}
public Builder setType(java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
result.hasType = true;
result.type_ = value;
return this;
}
public Builder clearType() {
result.hasType = false;
result.type_ = getDefaultInstance().getType();
return this;
}
// optional bytes indexdata = 2;
public boolean hasIndexdata() {
return result.hasIndexdata();
}
public com.google.protobuf.ByteString getIndexdata() {
return result.getIndexdata();
}
public Builder setIndexdata(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
result.hasIndexdata = true;
result.indexdata_ = value;
return this;
}
public Builder clearIndexdata() {
result.hasIndexdata = false;
result.indexdata_ = getDefaultInstance().getIndexdata();
return this;
}
// required int32 datasize = 3;
public boolean hasDatasize() {
return result.hasDatasize();
}
public int getDatasize() {
return result.getDatasize();
}
public Builder setDatasize(int value) {
result.hasDatasize = true;
result.datasize_ = value;
return this;
}
public Builder clearDatasize() {
result.hasDatasize = false;
result.datasize_ = 0;
return this;
}
// @@protoc_insertion_point(builder_scope:BlockHeader)
}
static {
defaultInstance = new BlockHeader(true);
crosby.binary.Fileformat.internalForceInit();
defaultInstance.initFields();
}
// @@protoc_insertion_point(class_scope:BlockHeader)
}
private static com.google.protobuf.Descriptors.Descriptor
internal_static_Blob_descriptor;
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_Blob_fieldAccessorTable;
private static com.google.protobuf.Descriptors.Descriptor
internal_static_BlockHeader_descriptor;
private static
com.google.protobuf.GeneratedMessage.FieldAccessorTable
internal_static_BlockHeader_fieldAccessorTable;
public static com.google.protobuf.Descriptors.FileDescriptor
getDescriptor() {
return descriptor;
}
private static com.google.protobuf.Descriptors.FileDescriptor
descriptor;
static {
java.lang.String[] descriptorData = {
"\n\020fileformat.proto\"_\n\004Blob\022\013\n\003raw\030\001 \001(\014\022" +
"\020\n\010raw_size\030\002 \001(\005\022\021\n\tzlib_data\030\003 \001(\014\022\021\n\t" +
"lzma_data\030\004 \001(\014\022\022\n\nbzip2_data\030\005 \001(\014\"@\n\013B" +
"lockHeader\022\014\n\004type\030\001 \002(\t\022\021\n\tindexdata\030\002 " +
"\001(\014\022\020\n\010datasize\030\003 \002(\005B\017\n\rcrosby.binary"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
public com.google.protobuf.ExtensionRegistry assignDescriptors(
com.google.protobuf.Descriptors.FileDescriptor root) {
descriptor = root;
internal_static_Blob_descriptor =
getDescriptor().getMessageTypes().get(0);
internal_static_Blob_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_Blob_descriptor,
new java.lang.String[] { "Raw", "RawSize", "ZlibData", "LzmaData", "Bzip2Data", },
crosby.binary.Fileformat.Blob.class,
crosby.binary.Fileformat.Blob.Builder.class);
internal_static_BlockHeader_descriptor =
getDescriptor().getMessageTypes().get(1);
internal_static_BlockHeader_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_BlockHeader_descriptor,
new java.lang.String[] { "Type", "Indexdata", "Datasize", },
crosby.binary.Fileformat.BlockHeader.class,
crosby.binary.Fileformat.BlockHeader.Builder.class);
return null;
}
};
com.google.protobuf.Descriptors.FileDescriptor
.internalBuildGeneratedFileFrom(descriptorData,
new com.google.protobuf.Descriptors.FileDescriptor[] {
}, assigner);
}
public static void internalForceInit() {}
// @@protoc_insertion_point(outer_class_scope)
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
package crosby.binary;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import com.google.protobuf.ByteString;
/**
* Class for mapping a set of strings to integers, giving frequently occuring
* strings small integers.
*/
public class StringTable {
public StringTable() {
clear();
}
private HashMap<String, Integer> counts;
private HashMap<String, Integer> stringmap;
private String set[];
public void incr(String s) {
if (counts.containsKey(s)) {
counts.put(s, new Integer(counts.get(s).intValue() + 1));
} else {
counts.put(s, new Integer(1));
}
}
/** After the stringtable has been built, return the offset of a string in it.
*
* Note, value '0' is reserved for use as a delimiter and will not be returned.
* @param s
* @return
*/
public int getIndex(String s) {
return stringmap.get(s).intValue();
}
public void finish() {
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(final String s1, String s2) {
int diff = counts.get(s2) - counts.get(s1);
return diff;
}
};
set = counts.keySet().toArray(new String[0]);
if (set.length > 0) {
// Sort based on the frequency.
Arrays.sort(set, comparator);
// Each group of keys that serializes to the same number of bytes is
// sorted lexiconographically.
// to maximize deflate compression.
// Don't sort the first array. There's not likely to be much benefit, and we want frequent values to be small.
//Arrays.sort(set, Math.min(0, set.length-1), Math.min(1 << 7, set.length-1));
Arrays.sort(set, Math.min(1 << 7, set.length-1), Math.min(1 << 14,
set.length-1));
Arrays.sort(set, Math.min(1 << 14, set.length-1), Math.min(1 << 21,
set.length-1), comparator);
}
stringmap = new HashMap<String, Integer>(2 * set.length);
for (int i = 0; i < set.length; i++) {
stringmap.put(set[i], new Integer(i+1)); // Index 0 is reserved for use as a delimiter.
}
counts = null;
}
public void clear() {
counts = new HashMap<String, Integer>(100);
stringmap = null;
set = null;
}
public Osmformat.StringTable.Builder serialize() {
Osmformat.StringTable.Builder builder = Osmformat.StringTable
.newBuilder();
builder.addS(ByteString.copyFromUtf8("")); // Add a unused string at offset 0 which is used as a delimiter.
for (int i = 0; i < set.length; i++)
builder.addS(ByteString.copyFromUtf8(set[i]));
return builder;
}
}

View file

@ -0,0 +1,26 @@
package crosby.binary.file;
import java.io.IOException;
import java.io.InputStream;
public class BlockInputStream {
// TODO: Should be seekable input stream!
public BlockInputStream(InputStream input, BlockReaderAdapter adaptor) {
this.input = input;
this.adaptor = adaptor;
}
public void process() throws IOException {
while (input.available() > 0) {
FileBlock.process(input, adaptor);
}
adaptor.complete();
}
public void close() throws IOException {
input.close();
}
InputStream input;
BlockReaderAdapter adaptor;
}

View file

@ -0,0 +1,58 @@
package crosby.binary.file;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class BlockOutputStream {
public enum CompressFlags {
NONE, DEFLATE
}
public BlockOutputStream(OutputStream output) {
this.outwrite = new DataOutputStream(output);
this.compression = CompressFlags.DEFLATE;
}
public void setCompress(CompressFlags flag) {
compression = flag;
}
public void setCompress(String s) {
if (s.equals("none"))
compression = CompressFlags.NONE;
else if (s.equals("deflate"))
compression = CompressFlags.DEFLATE;
else
throw new Error("Unknown compression type: " + s);
}
/** Write a block with the stream's default compression flag */
public void write(FileBlock block) throws IOException {
this.write(block, compression);
}
/** Write a specific block with a specific compression flags */
public void write(FileBlock block, CompressFlags compression)
throws IOException {
FileBlockPosition ref = block.writeTo(outwrite, compression);
writtenblocks.add(ref);
}
public void flush() throws IOException {
outwrite.flush();
}
public void close() throws IOException {
outwrite.flush();
outwrite.close();
}
OutputStream outwrite;
List<FileBlockPosition> writtenblocks = new ArrayList<FileBlockPosition>();
CompressFlags compression;
}

View file

@ -0,0 +1,23 @@
package crosby.binary.file;
/** An adaptor that receives blocks from an input stream */
public interface BlockReaderAdapter {
/**
* Does the reader understand this block? Does it want the data in it?
*
* A reference contains the metadata about a block and can saved --- or
* stored ---- for future random access. However, during a strea read of the
* file, does the user want this block?
*
* handleBlock will be called on all blocks that are not skipped, in file
* order.
*
* */
boolean skipBlock(FileBlockPosition message);
/** Called with the data in the block. */
void handleBlock(FileBlock message);
/** Called when the file is fully read. */
void complete();
}

View file

@ -0,0 +1,128 @@
package crosby.binary.file;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.zip.Deflater;
import com.google.protobuf.ByteString;
import crosby.binary.Fileformat;
import crosby.binary.Fileformat.BlockHeader;
import crosby.binary.file.BlockOutputStream.CompressFlags;
/** A full fileblock object contains both the metadata and data of a fileblock */
public class FileBlock extends FileBlockBase {
/** Contains the contents of a block for use or further processing */
ByteString data; // serialized Format.Blob
/** Don't be noisy unless the warning occurs somewhat often */
static int warncount = 0;
private FileBlock(String type, ByteString blob, ByteString indexdata) {
super(type, indexdata);
this.data = blob;
}
public static FileBlock newInstance(String type, ByteString blob,
ByteString indexdata) {
if (blob != null && blob.size() > MAX_BODY_SIZE/2) {
System.err.println("Warning: Fileblock has body size too large and may be considered corrupt");
if (blob != null && blob.size() > MAX_BODY_SIZE-1024*1024) {
throw new Error("This file has too many entities in a block. Parsers will reject it.");
}
}
if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE/2) {
System.err.println("Warning: Fileblock has indexdata too large and may be considered corrupt");
if (indexdata != null && indexdata.size() > MAX_HEADER_SIZE-512) {
throw new Error("This file header is too large. Parsers will reject it.");
}
}
return new FileBlock(type, blob, indexdata);
}
protected void deflateInto(crosby.binary.Fileformat.Blob.Builder blobbuilder) {
int size = data.size();
Deflater deflater = new Deflater();
deflater.setInput(data.toByteArray());
deflater.finish();
byte out[] = new byte[size];
deflater.deflate(out);
if (!deflater.finished()) {
// Buffer wasn't long enough. Be noisy.
++warncount;
if (warncount > 10 && warncount%100 == 0)
System.out.println("Compressed buffers are too short, causing extra copy");
int newLength = size + size / 64 + 16;
byte[] copy = new byte[newLength];
System.arraycopy(out, 0, copy, 0, Math.min(out.length, newLength));
out = copy;
deflater.deflate(out, deflater.getTotalOut(), out.length - deflater.getTotalOut());
if (!deflater.finished()) {
throw new Error("Internal error in compressor");
}
}
ByteString compressed = ByteString.copyFrom(out, 0, deflater
.getTotalOut());
blobbuilder.setZlibData(compressed);
deflater.end();
}
public FileBlockPosition writeTo(OutputStream outwrite, CompressFlags flags)
throws IOException {
BlockHeader.Builder builder = Fileformat.BlockHeader
.newBuilder();
if (indexdata != null)
builder.setIndexdata(indexdata);
builder.setType(type);
Fileformat.Blob.Builder blobbuilder = Fileformat.Blob.newBuilder();
if (flags == CompressFlags.NONE) {
blobbuilder.setRaw(data);
} else {
blobbuilder.setRawSize(data.size());
if (flags == CompressFlags.DEFLATE)
deflateInto(blobbuilder);
else
throw new Error("Compression flag not understood");
}
Fileformat.Blob blob = blobbuilder.build();
builder.setDatasize(blob.getSerializedSize());
Fileformat.BlockHeader message = builder.build();
int size = message.getSerializedSize();
// System.out.format("Outputed header size %d bytes, header of %d bytes, and blob of %d bytes\n",
// size,message.getSerializedSize(),blob.getSerializedSize());
(new DataOutputStream(outwrite)).writeInt(size);
message.writeTo(outwrite);
long offset = -1;
if (outwrite instanceof FileOutputStream)
offset = ((FileOutputStream) outwrite).getChannel().position();
blob.writeTo(outwrite);
return FileBlockPosition.newInstance(this, offset, size);
}
/** Reads or skips a fileblock. */
static void process(InputStream input, BlockReaderAdapter callback)
throws IOException {
FileBlockHead fileblock = FileBlockHead.readHead(input);
if (callback.skipBlock(fileblock)) {
// System.out.format("Attempt to skip %d bytes\n",header.getDatasize());
fileblock.skipContents(input);
} else {
callback.handleBlock(fileblock.readContents(input));
}
}
public ByteString getData() {
return data;
}
}

View file

@ -0,0 +1,41 @@
package crosby.binary.file;
import com.google.protobuf.ByteString;
/**
* Base class that contains the metadata about a fileblock.
*
* Subclasses of this include additional fields, such as byte offsets that let a
* fileblock be read in a random-access fashion, or the data itself.
*
* @author crosby
*
*/
public class FileBlockBase {
/** If a block header is bigger than this, fail. We use excessively large header size as an indication of corrupt files */
static final int MAX_HEADER_SIZE = 64*1024;
/** If a block's size is bigger than this, fail. We use excessively large block sizes as an indication of corrupt files */
static final int MAX_BODY_SIZE = 32*1024*1024;
protected FileBlockBase(String type, ByteString indexdata) {
this.type = type;
this.indexdata = indexdata;
}
/** Identifies the type of the data within a block */
protected final String type;
/**
* Block metadata, stored in the index block and as a prefix for every
* block.
*/
protected final ByteString indexdata;
public String getType() {
return type;
}
public ByteString getIndexData() {
return indexdata;
}
}

View file

@ -0,0 +1,80 @@
package crosby.binary.file;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.google.protobuf.ByteString;
import crosby.binary.Fileformat;
/**
* Intermediate representation of the header of a fileblock when a set of
* fileblocks is read as in a stream. The data in the fileblock must be either
* skipped (where the returned value is a reference to the fileblock) or parsed.
*
* @author crosby
*
*/
public class FileBlockHead extends FileBlockReference {
protected FileBlockHead(String type, ByteString indexdata) {
super(type, indexdata);
}
/**
* Read the header. After reading the header, either the contents must be
* skipped or read
*/
static FileBlockHead readHead(InputStream input) throws IOException {
DataInputStream datinput = new DataInputStream(input);
int headersize = datinput.readInt();
// System.out.format("Header size %d %x\n",headersize,headersize);
if (headersize > MAX_HEADER_SIZE) {
throw new FileFormatException("Unexpectedly long header "+MAX_HEADER_SIZE+ " bytes. Possibly corrupt file.");
}
byte buf[] = new byte[headersize];
datinput.readFully(buf);
// System.out.format("Read buffer for header of %d bytes\n",buf.length);
Fileformat.BlockHeader header = Fileformat.BlockHeader
.parseFrom(buf);
FileBlockHead fileblock = new FileBlockHead(header.getType(), header
.getIndexdata());
fileblock.datasize = header.getDatasize();
if (header.getDatasize() > MAX_BODY_SIZE) {
throw new FileFormatException("Unexpectedly long body "+MAX_BODY_SIZE+ " bytes. Possibly corrupt file.");
}
fileblock.input = input;
if (input instanceof FileInputStream)
fileblock.data_offset = ((FileInputStream) input).getChannel()
.position();
return fileblock;
}
/**
* Assumes the stream is positioned over at the start of the data, skip over
* it.
*
* @throws IOException
*/
void skipContents(InputStream input) throws IOException {
if (input.skip(getDatasize()) != getDatasize())
assert false : "SHORT READ";
}
/**
* Assumes the stream is positioned over at the start of the data, read it
* and return the complete FileBlock
*
* @throws IOException
*/
FileBlock readContents(InputStream input) throws IOException {
DataInputStream datinput = new DataInputStream(input);
byte buf[] = new byte[getDatasize()];
datinput.readFully(buf);
return parseData(buf);
}
}

View file

@ -0,0 +1,95 @@
package crosby.binary.file;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import crosby.binary.Fileformat;
/**
* Stores the position in the stream of a fileblock so that it can be easily
* read in a random-access fashion.
*
* We can turn this into a 'real' block by appropriately seeking into the file
* and doing a 'read'.
*
* */
public class FileBlockPosition extends FileBlockBase {
protected FileBlockPosition(String type, ByteString indexdata) {
super(type, indexdata);
}
/** Parse out and decompress the data part of a fileblock helper function. */
FileBlock parseData(byte buf[]) throws InvalidProtocolBufferException {
FileBlock out = FileBlock.newInstance(type, null, indexdata);
Fileformat.Blob blob = Fileformat.Blob.parseFrom(buf);
if (blob.hasRaw()) {
out.data = blob.getRaw();
} else if (blob.hasZlibData()) {
byte buf2[] = new byte[blob.getRawSize()];
Inflater decompresser = new Inflater();
decompresser.setInput(blob.getZlibData().toByteArray());
// decompresser.getRemaining();
try {
decompresser.inflate(buf2);
} catch (DataFormatException e) {
e.printStackTrace();
throw new Error(e);
}
assert (decompresser.finished());
decompresser.end();
out.data = ByteString.copyFrom(buf2);
}
return out;
}
public int getDatasize() {
return datasize;
}
/*
* Given any form of fileblock and an offset/length value, return a
* reference that can be used to dereference and read the contents.
*/
static FileBlockPosition newInstance(FileBlockBase base, long offset,
int length) {
FileBlockPosition out = new FileBlockPosition(base.type, base.indexdata);
out.datasize = length;
out.data_offset = offset;
return out;
}
public FileBlock read(InputStream input) throws IOException {
if (input instanceof FileInputStream) {
((FileInputStream) input).getChannel().position(data_offset);
byte buf[] = new byte[getDatasize()];
(new DataInputStream(input)).readFully(buf);
return parseData(buf);
} else {
throw new Error("Random access binary reads require seekability");
}
}
/**
* TODO: Convert this reference into a serialized representation that can be
* stored.
*/
public ByteString serialize() {
throw new Error("TODO");
}
/** TODO: Parse a serialized representation of this block reference */
static FileBlockPosition parseFrom(ByteString b) {
throw new Error("TODO");
}
protected int datasize;
/** Offset into the file of the data part of the block */
long data_offset;
}

View file

@ -0,0 +1,37 @@
package crosby.binary.file;
import java.io.IOException;
import java.io.InputStream;
import com.google.protobuf.ByteString;
/**
* A FileBlockPosition that remembers what file this is so that it can simply be
* dereferenced
*/
public class FileBlockReference extends FileBlockPosition {
/**
* Convenience cache for storing the input this reference is contained
* within so that it can be cached
*/
protected InputStream input;
protected FileBlockReference(String type, ByteString indexdata) {
super(type, indexdata);
}
public FileBlock read() throws IOException {
return read(input);
}
static FileBlockPosition newInstance(FileBlockBase base, InputStream input,
long offset, int length) {
FileBlockReference out = new FileBlockReference(base.type,
base.indexdata);
out.datasize = length;
out.data_offset = offset;
out.input = input;
return out;
}
}

View file

@ -0,0 +1,16 @@
package crosby.binary.file;
import java.io.IOException;
public class FileFormatException extends IOException {
public FileFormatException(String string) {
super(string);
}
/**
*
*/
private static final long serialVersionUID = -8128010128748910923L;
}

View file

@ -0,0 +1,28 @@
option java_package = "crosby.binary";
//protoc --java_out=../.. fileformat.proto
//
// STORAGE LAYER: Storing primitives.
//
message Blob {
optional bytes raw = 1; // No compression
optional int32 raw_size = 2; // When compressed, the uncompressed size
// Possible compressed versions of the data.
optional bytes zlib_data = 3;
optional bytes lzma_data = 4;
optional bytes bzip2_data = 5;
}
/* A file contains an sequence of fileblock headers, each prefixed by
their length, followed by a data block containing the actual data.
types staring with a "_" are reserved.
*/
message BlockHeader {
required string type = 1;
optional bytes indexdata = 2;
required int32 datasize = 3;
}

View file

@ -0,0 +1,316 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TFloatIterator;
import gnu.trove.procedure.TFloatProcedure;
import java.util.Collection;
import java.io.Serializable;
/**
* An interface that mimics the <tt>Collection</tt> interface.
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $
*/
public interface TFloatCollection extends Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
float getNoEntryValue();
/**
* Returns the number of elements in this collection (its cardinality). If this
* collection contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this collection (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this collection contains no elements.
*
* @return <tt>true</tt> if this collection contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this collection contains the specified element.
*
* @param entry an <code>float</code> value
* @return true if the collection contains the specified element.
*/
boolean contains( float entry );
/**
* Creates an iterator over the values of the collection. The iterator
* supports element deletion.
*
* @return an <code>TFloatIterator</code> value
*/
TFloatIterator iterator();
/**
* Returns an array containing all of the elements in this collection.
* If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this collection. (In other words, this method must
* allocate a new array even if this collection is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this collection
*/
float[] toArray();
/**
* Returns an array containing elements in this collection.
*
* <p>If this collection fits in the specified array with room to spare
* (i.e., the array has more elements than this collection), the element in
* the array immediately following the end of the collection is collection to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this collection <i>only</i> if the caller knows that this
* collection does not contain any elements representing null.)
*
* <p>If the native array is smaller than the collection size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this collection are to be
* stored.
* @return an <tt>float[]</tt> containing all the elements in this collection
* @throws NullPointerException if the specified array is null
*/
float[] toArray( float[] dest );
/**
* Inserts a value into the collection.
*
* @param entry a <code>float</code> value
* @return true if the collection was modified by the add operation
*/
boolean add( float entry );
/**
* Removes <tt>entry</tt> from the collection.
*
* @param entry an <code>float</code> value
* @return true if the collection was modified by the remove operation.
*/
boolean remove( float entry );
/**
* Tests the collection to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>TFloatCollection</tt> are present.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( TFloatCollection collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of float primitives.
* @return true if all elements were present in the collection.
*/
boolean containsAll( float[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( Collection<? extends Float> collection );
/**
* Adds all of the elements in the <tt>TFloatCollection</tt> to the collection.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( TFloatCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the collection.
*
* @param array a <code>array</code> of float primitives.
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( float[] array );
/**
* Removes any values in the collection which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the collection which are not contained in
* <tt>TFloatCollection</tt>.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( TFloatCollection collection );
/**
* Removes any values in the collection which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of float primitives.
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( float[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TFloatCollection</tt> from the collection.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( TFloatCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the collection.
*
* @param array an <code>array</code> of float primitives.
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( float[] array );
/**
* Empties the collection.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the collection.
*
* @param procedure a <code>TFloatProcedure</code> value
* @return false if the loop over the collection terminated because
* the procedure returned false for some value.
*/
boolean forEach( TFloatProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this collection for equality. Returns
* <tt>true</tt> if the specified object is also a collection, the two collection
* have the same size, and every member of the specified collection is
* contained in this collection (or equivalently, every member of this collection is
* contained in the specified collection). This definition ensures that the
* equals method works properly across different implementations of the
* collection interface.
*
* @param o object to be compared for equality with this collection
* @return <tt>true</tt> if the specified object is equal to this collection
*/
boolean equals( Object o );
/**
* Returns the hash code value for this collection. The hash code of a collection is
* defined to be the sum of the hash codes of the elements in the collection.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two collection <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this collection
* @see Object#equals(Object)
* @see Collection#equals(Object)
*/
int hashCode();
} // TFloatCollection

View file

@ -0,0 +1,316 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TIntIterator;
import gnu.trove.procedure.TIntProcedure;
import java.util.Collection;
import java.io.Serializable;
/**
* An interface that mimics the <tt>Collection</tt> interface.
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $
*/
public interface TIntCollection extends Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
int getNoEntryValue();
/**
* Returns the number of elements in this collection (its cardinality). If this
* collection contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this collection (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this collection contains no elements.
*
* @return <tt>true</tt> if this collection contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this collection contains the specified element.
*
* @param entry an <code>int</code> value
* @return true if the collection contains the specified element.
*/
boolean contains( int entry );
/**
* Creates an iterator over the values of the collection. The iterator
* supports element deletion.
*
* @return an <code>TIntIterator</code> value
*/
TIntIterator iterator();
/**
* Returns an array containing all of the elements in this collection.
* If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this collection. (In other words, this method must
* allocate a new array even if this collection is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this collection
*/
int[] toArray();
/**
* Returns an array containing elements in this collection.
*
* <p>If this collection fits in the specified array with room to spare
* (i.e., the array has more elements than this collection), the element in
* the array immediately following the end of the collection is collection to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this collection <i>only</i> if the caller knows that this
* collection does not contain any elements representing null.)
*
* <p>If the native array is smaller than the collection size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this collection are to be
* stored.
* @return an <tt>int[]</tt> containing all the elements in this collection
* @throws NullPointerException if the specified array is null
*/
int[] toArray( int[] dest );
/**
* Inserts a value into the collection.
*
* @param entry a <code>int</code> value
* @return true if the collection was modified by the add operation
*/
boolean add( int entry );
/**
* Removes <tt>entry</tt> from the collection.
*
* @param entry an <code>int</code> value
* @return true if the collection was modified by the remove operation.
*/
boolean remove( int entry );
/**
* Tests the collection to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>TIntCollection</tt> are present.
*
* @param collection a <code>TIntCollection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( TIntCollection collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of int primitives.
* @return true if all elements were present in the collection.
*/
boolean containsAll( int[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( Collection<? extends Integer> collection );
/**
* Adds all of the elements in the <tt>TIntCollection</tt> to the collection.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( TIntCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the collection.
*
* @param array a <code>array</code> of int primitives.
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( int[] array );
/**
* Removes any values in the collection which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the collection which are not contained in
* <tt>TIntCollection</tt>.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( TIntCollection collection );
/**
* Removes any values in the collection which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of int primitives.
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( int[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TIntCollection</tt> from the collection.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( TIntCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the collection.
*
* @param array an <code>array</code> of int primitives.
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( int[] array );
/**
* Empties the collection.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the collection.
*
* @param procedure a <code>TIntProcedure</code> value
* @return false if the loop over the collection terminated because
* the procedure returned false for some value.
*/
boolean forEach( TIntProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this collection for equality. Returns
* <tt>true</tt> if the specified object is also a collection, the two collection
* have the same size, and every member of the specified collection is
* contained in this collection (or equivalently, every member of this collection is
* contained in the specified collection). This definition ensures that the
* equals method works properly across different implementations of the
* collection interface.
*
* @param o object to be compared for equality with this collection
* @return <tt>true</tt> if the specified object is equal to this collection
*/
boolean equals( Object o );
/**
* Returns the hash code value for this collection. The hash code of a collection is
* defined to be the sum of the hash codes of the elements in the collection.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two collection <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this collection
* @see Object#equals(Object)
* @see Collection#equals(Object)
*/
int hashCode();
} // TIntCollection

View file

@ -0,0 +1,316 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TLongIterator;
import gnu.trove.procedure.TLongProcedure;
import java.util.Collection;
import java.io.Serializable;
/**
* An interface that mimics the <tt>Collection</tt> interface.
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: _E_Collection.template,v 1.1.2.2 2009/09/15 02:38:30 upholderoftruth Exp $
*/
public interface TLongCollection extends Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
long getNoEntryValue();
/**
* Returns the number of elements in this collection (its cardinality). If this
* collection contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this collection (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this collection contains no elements.
*
* @return <tt>true</tt> if this collection contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this collection contains the specified element.
*
* @param entry an <code>long</code> value
* @return true if the collection contains the specified element.
*/
boolean contains( long entry );
/**
* Creates an iterator over the values of the collection. The iterator
* supports element deletion.
*
* @return an <code>TLongIterator</code> value
*/
TLongIterator iterator();
/**
* Returns an array containing all of the elements in this collection.
* If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this collection. (In other words, this method must
* allocate a new array even if this collection is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this collection
*/
long[] toArray();
/**
* Returns an array containing elements in this collection.
*
* <p>If this collection fits in the specified array with room to spare
* (i.e., the array has more elements than this collection), the element in
* the array immediately following the end of the collection is collection to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this collection <i>only</i> if the caller knows that this
* collection does not contain any elements representing null.)
*
* <p>If the native array is smaller than the collection size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this collection are to be
* stored.
* @return an <tt>long[]</tt> containing all the elements in this collection
* @throws NullPointerException if the specified array is null
*/
long[] toArray( long[] dest );
/**
* Inserts a value into the collection.
*
* @param entry a <code>long</code> value
* @return true if the collection was modified by the add operation
*/
boolean add( long entry );
/**
* Removes <tt>entry</tt> from the collection.
*
* @param entry an <code>long</code> value
* @return true if the collection was modified by the remove operation.
*/
boolean remove( long entry );
/**
* Tests the collection to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>TLongCollection</tt> are present.
*
* @param collection a <code>TLongCollection</code> value
* @return true if all elements were present in the collection.
*/
boolean containsAll( TLongCollection collection );
/**
* Tests the collection to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of long primitives.
* @return true if all elements were present in the collection.
*/
boolean containsAll( long[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( Collection<? extends Long> collection );
/**
* Adds all of the elements in the <tt>TLongCollection</tt> to the collection.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( TLongCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the collection.
*
* @param array a <code>array</code> of long primitives.
* @return true if the collection was modified by the add all operation.
*/
boolean addAll( long[] array );
/**
* Removes any values in the collection which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the collection which are not contained in
* <tt>TLongCollection</tt>.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( TLongCollection collection );
/**
* Removes any values in the collection which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of long primitives.
* @return true if the collection was modified by the retain all operation
*/
boolean retainAll( long[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the collection.
*
* @param collection a <code>Collection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TLongCollection</tt> from the collection.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( TLongCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the collection.
*
* @param array an <code>array</code> of long primitives.
* @return true if the collection was modified by the remove all operation.
*/
boolean removeAll( long[] array );
/**
* Empties the collection.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the collection.
*
* @param procedure a <code>TLongProcedure</code> value
* @return false if the loop over the collection terminated because
* the procedure returned false for some value.
*/
boolean forEach( TLongProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this collection for equality. Returns
* <tt>true</tt> if the specified object is also a collection, the two collection
* have the same size, and every member of the specified collection is
* contained in this collection (or equivalently, every member of this collection is
* contained in the specified collection). This definition ensures that the
* equals method works properly across different implementations of the
* collection interface.
*
* @param o object to be compared for equality with this collection
* @return <tt>true</tt> if the specified object is equal to this collection
*/
boolean equals( Object o );
/**
* Returns the hash code value for this collection. The hash code of a collection is
* defined to be the sum of the hash codes of the elements in the collection.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two collection <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this collection
* @see Object#equals(Object)
* @see Collection#equals(Object)
*/
int hashCode();
} // TLongCollection

View file

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.function;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for functions that accept and return one float primitive.
*/
public interface TFloatFunction {
/**
* Execute this function with <tt>value</tt>
*
* @param value a <code>float</code> input
* @return a <code>float</code> result
*/
public float execute( float value );
}

View file

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.function;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for functions that accept and return one int primitive.
*/
public interface TIntFunction {
/**
* Execute this function with <tt>value</tt>
*
* @param value a <code>int</code> input
* @return a <code>int</code> result
*/
public int execute( int value );
}

View file

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.function;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for functions that accept and return one long primitive.
*/
public interface TLongFunction {
/**
* Execute this function with <tt>value</tt>
*
* @param value a <code>long</code> input
* @return a <code>long</code> result
*/
public long execute( long value );
}

View file

@ -0,0 +1,39 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.function;
/**
* Interface for functions that accept and return one Object reference.
* <p/>
* Created: Mon Nov 5 22:19:36 2001
*
* @author Eric D. Friedman
* @version $Id: TObjectFunction.java,v 1.1.2.1 2009/09/06 17:02:19 upholderoftruth Exp $
*/
public interface TObjectFunction<T, R> {
/**
* Execute this function with <tt>value</tt>
*
* @param value an <code>Object</code> input
* @return an <code>Object</code> result
*/
public R execute( T value );
}// TObjectFunction

View file

@ -0,0 +1,165 @@
// ////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// ////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl;
/**
* Central location for constants needed by various implementations.
*/
public class Constants {
private static final boolean VERBOSE =
System.getProperty( "gnu.trove.verbose", null ) != null;
/** the default capacity for new collections */
public static final int DEFAULT_CAPACITY = 10;
/** the load above which rehashing occurs. */
public static final float DEFAULT_LOAD_FACTOR = 0.5f;
/** the default value that represents for <tt>byte</tt> types. */
public static final byte DEFAULT_BYTE_NO_ENTRY_VALUE;
static {
byte value;
String property = System.getProperty( "gnu.trove.no_entry.byte", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Byte.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Byte.MIN_VALUE;
else value = Byte.valueOf( property );
if ( value > Byte.MAX_VALUE ) value = Byte.MAX_VALUE;
else if ( value < Byte.MIN_VALUE ) value = Byte.MIN_VALUE;
DEFAULT_BYTE_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_BYTE_NO_ENTRY_VALUE: " +
DEFAULT_BYTE_NO_ENTRY_VALUE );
}
}
/** the default value that represents for <tt>short</tt> types. */
public static final short DEFAULT_SHORT_NO_ENTRY_VALUE;
static {
short value;
String property = System.getProperty( "gnu.trove.no_entry.short", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Short.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Short.MIN_VALUE;
else value = Short.valueOf( property );
if ( value > Short.MAX_VALUE ) value = Short.MAX_VALUE;
else if ( value < Short.MIN_VALUE ) value = Short.MIN_VALUE;
DEFAULT_SHORT_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_SHORT_NO_ENTRY_VALUE: " +
DEFAULT_SHORT_NO_ENTRY_VALUE );
}
}
/** the default value that represents for <tt>char</tt> types. */
public static final char DEFAULT_CHAR_NO_ENTRY_VALUE;
static {
char value;
String property = System.getProperty( "gnu.trove.no_entry.char", "\0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Character.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Character.MIN_VALUE;
else value = property.toCharArray()[0];
if ( value > Character.MAX_VALUE ) value = Character.MAX_VALUE;
else if ( value < Character.MIN_VALUE ) value = Character.MIN_VALUE;
DEFAULT_CHAR_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_CHAR_NO_ENTRY_VALUE: " +
Integer.valueOf( value ) );
}
}
/** the default value that represents for <tt>int</tt> types. */
public static final int DEFAULT_INT_NO_ENTRY_VALUE;
static {
int value;
String property = System.getProperty( "gnu.trove.no_entry.int", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Integer.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Integer.MIN_VALUE;
else value = Integer.valueOf( property );
DEFAULT_INT_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_INT_NO_ENTRY_VALUE: " +
DEFAULT_INT_NO_ENTRY_VALUE );
}
}
/** the default value that represents for <tt>long</tt> types. */
public static final long DEFAULT_LONG_NO_ENTRY_VALUE;
static {
long value;
String property = System.getProperty( "gnu.trove.no_entry.long", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Long.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Long.MIN_VALUE;
else value = Long.valueOf( property );
DEFAULT_LONG_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_LONG_NO_ENTRY_VALUE: " +
DEFAULT_LONG_NO_ENTRY_VALUE );
}
}
/** the default value that represents for <tt>float</tt> types. */
public static final float DEFAULT_FLOAT_NO_ENTRY_VALUE;
static {
float value;
String property = System.getProperty( "gnu.trove.no_entry.float", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Float.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Float.MIN_VALUE;
// Value from Float.MIN_NORMAL (introduced in 1.6)
else if ( "MIN_NORMAL".equalsIgnoreCase( property ) ) value = 0x1.0p-126f;
else if ( "NEGATIVE_INFINITY".equalsIgnoreCase( property ) ) value = Float.NEGATIVE_INFINITY;
else if ( "POSITIVE_INFINITY".equalsIgnoreCase( property ) ) value = Float.POSITIVE_INFINITY;
// else if ( "NaN".equalsIgnoreCase( property ) ) value = Float.NaN;
else value = Float.valueOf( property );
DEFAULT_FLOAT_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_FLOAT_NO_ENTRY_VALUE: " +
DEFAULT_FLOAT_NO_ENTRY_VALUE );
}
}
/** the default value that represents for <tt>double</tt> types. */
public static final double DEFAULT_DOUBLE_NO_ENTRY_VALUE;
static {
double value;
String property = System.getProperty( "gnu.trove.no_entry.double", "0" );
if ( "MAX_VALUE".equalsIgnoreCase( property ) ) value = Double.MAX_VALUE;
else if ( "MIN_VALUE".equalsIgnoreCase( property ) ) value = Double.MIN_VALUE;
// Value from Double.MIN_NORMAL (introduced in 1.6)
else if ( "MIN_NORMAL".equalsIgnoreCase( property ) ) value = 0x1.0p-1022;
else if ( "NEGATIVE_INFINITY".equalsIgnoreCase( property ) ) value = Double.NEGATIVE_INFINITY;
else if ( "POSITIVE_INFINITY".equalsIgnoreCase( property ) ) value = Double.POSITIVE_INFINITY;
// else if ( "NaN".equalsIgnoreCase( property ) ) value = Double.NaN;
else value = Double.valueOf( property );
DEFAULT_DOUBLE_NO_ENTRY_VALUE = value;
if ( VERBOSE ) {
System.out.println( "DEFAULT_DOUBLE_NO_ENTRY_VALUE: " +
DEFAULT_DOUBLE_NO_ENTRY_VALUE );
}
}
}

View file

@ -0,0 +1,87 @@
// Copyright (c) 1999 CERN - European Organization for Nuclear Research.
// Permission to use, copy, modify, distribute and sell this software and
// its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and that
// both that copyright notice and this permission notice appear in
// supporting documentation. CERN makes no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without expressed or implied warranty.
package gnu.trove.impl;
/**
* Provides various hash functions.
*
* @author wolfgang.hoschek@cern.ch
* @version 1.0, 09/24/99
*/
public final class HashFunctions {
/**
* Returns a hashcode for the specified value.
*
* @return a hash code value for the specified value.
*/
public static int hash(double value) {
assert !Double.isNaN(value) : "Values of NaN are not supported.";
long bits = Double.doubleToLongBits(value);
return (int)(bits ^ (bits >>> 32));
//return (int) Double.doubleToLongBits(value*663608941.737);
//this avoids excessive hashCollisions in the case values are
//of the form (1.0, 2.0, 3.0, ...)
}
/**
* Returns a hashcode for the specified value.
*
* @return a hash code value for the specified value.
*/
public static int hash(float value) {
assert !Float.isNaN(value) : "Values of NaN are not supported.";
return Float.floatToIntBits(value*663608941.737f);
// this avoids excessive hashCollisions in the case values are
// of the form (1.0, 2.0, 3.0, ...)
}
/**
* Returns a hashcode for the specified value.
*
* @return a hash code value for the specified value.
*/
public static int hash(int value) {
// Multiply by prime to make sure hash can't be negative (see Knuth v3, p. 515-516)
return value * 31;
}
/**
* Returns a hashcode for the specified value.
*
* @return a hash code value for the specified value.
*/
public static int hash(long value) {
// Multiply by prime to make sure hash can't be negative (see Knuth v3, p. 515-516)
return ((int)(value ^ (value >>> 32))) * 31;
}
/**
* Returns a hashcode for the specified object.
*
* @return a hash code value for the specified object.
*/
public static int hash(Object object) {
return object==null ? 0 : object.hashCode();
}
/**
* In profiling, it has been found to be faster to have our own local implementation
* of "ceil" rather than to call to {@link Math#ceil(double)}.
*/
public static int fastCeil( float v ) {
int possible_result = ( int ) v;
if ( v - possible_result > 0 ) possible_result++;
return possible_result;
}
}

View file

@ -0,0 +1,158 @@
// Copyright (c) 1999 CERN - European Organization for Nuclear Research.
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear in
// supporting documentation. CERN makes no representations about the
// suitability of this software for any purpose. It is provided "as is"
// without expressed or implied warranty.
package gnu.trove.impl;
import java.util.Arrays;
/*
* Modified for Trove to use the java.util.Arrays sort/search
* algorithms instead of those provided with colt.
*/
/**
* Used to keep hash table capacities prime numbers.
* Not of interest for users; only for implementors of hashtables.
*
* <p>Choosing prime numbers as hash table capacities is a good idea
* to keep them working fast, particularly under hash table
* expansions.
*
* <p>However, JDK 1.2, JGL 3.1 and many other toolkits do nothing to
* keep capacities prime. This class provides efficient means to
* choose prime capacities.
*
* <p>Choosing a prime is <tt>O(log 300)</tt> (binary search in a list
* of 300 ints). Memory requirements: 1 KB static memory.
*
* @author wolfgang.hoschek@cern.ch
* @version 1.0, 09/24/99
*/
public final class PrimeFinder {
/**
* The largest prime this class can generate; currently equal to
* <tt>Integer.MAX_VALUE</tt>.
*/
public static final int largestPrime = Integer.MAX_VALUE; //yes, it is prime.
/**
* The prime number list consists of 11 chunks.
*
* Each chunk contains prime numbers.
*
* A chunk starts with a prime P1. The next element is a prime
* P2. P2 is the smallest prime for which holds: P2 >= 2*P1.
*
* The next element is P3, for which the same holds with respect
* to P2, and so on.
*
* Chunks are chosen such that for any desired capacity >= 1000
* the list includes a prime number <= desired capacity * 1.11.
*
* Therefore, primes can be retrieved which are quite close to any
* desired capacity, which in turn avoids wasting memory.
*
* For example, the list includes
* 1039,1117,1201,1277,1361,1439,1523,1597,1759,1907,2081.
*
* So if you need a prime >= 1040, you will find a prime <=
* 1040*1.11=1154.
*
* Chunks are chosen such that they are optimized for a hashtable
* growthfactor of 2.0;
*
* If your hashtable has such a growthfactor then, after initially
* "rounding to a prime" upon hashtable construction, it will
* later expand to prime capacities such that there exist no
* better primes.
*
* In total these are about 32*10=320 numbers -> 1 KB of static
* memory needed.
*
* If you are stingy, then delete every second or fourth chunk.
*/
private static final int[] primeCapacities = {
//chunk #0
largestPrime,
//chunk #1
5,11,23,47,97,197,397,797,1597,3203,6421,12853,25717,51437,102877,205759,
411527,823117,1646237,3292489,6584983,13169977,26339969,52679969,105359939,
210719881,421439783,842879579,1685759167,
//chunk #2
433,877,1759,3527,7057,14143,28289,56591,113189,226379,452759,905551,1811107,
3622219,7244441,14488931,28977863,57955739,115911563,231823147,463646329,927292699,
1854585413,
//chunk #3
953,1907,3821,7643,15287,30577,61169,122347,244703,489407,978821,1957651,3915341,
7830701,15661423,31322867,62645741,125291483,250582987,501165979,1002331963,
2004663929,
//chunk #4
1039,2081,4177,8363,16729,33461,66923,133853,267713,535481,1070981,2141977,4283963,
8567929,17135863,34271747,68543509,137087021,274174111,548348231,1096696463,
//chunk #5
31,67,137,277,557,1117,2237,4481,8963,17929,35863,71741,143483,286973,573953,
1147921,2295859,4591721,9183457,18366923,36733847,73467739,146935499,293871013,
587742049,1175484103,
//chunk #6
599,1201,2411,4831,9677,19373,38747,77509,155027,310081,620171,1240361,2480729,
4961459,9922933,19845871,39691759,79383533,158767069,317534141,635068283,1270136683,
//chunk #7
311,631,1277,2557,5119,10243,20507,41017,82037,164089,328213,656429,1312867,
2625761,5251529,10503061,21006137,42012281,84024581,168049163,336098327,672196673,
1344393353,
//chunk #8
3,7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87719,175447,350899,
701819,1403641,2807303,5614657,11229331,22458671,44917381,89834777,179669557,
359339171,718678369,1437356741,
//chunk #9
43,89,179,359,719,1439,2879,5779,11579,23159,46327,92657,185323,370661,741337,
1482707,2965421,5930887,11861791,23723597,47447201,94894427,189788857,379577741,
759155483,1518310967,
//chunk #10
379,761,1523,3049,6101,12203,24407,48817,97649,195311,390647,781301,1562611,
3125257,6250537,12501169,25002389,50004791,100009607,200019221,400038451,800076929,
1600153859
};
static { //initializer
// The above prime numbers are formatted for human readability.
// To find numbers fast, we sort them once and for all.
Arrays.sort(primeCapacities);
}
/**
* Returns a prime number which is <code>&gt;= desiredCapacity</code>
* and very close to <code>desiredCapacity</code> (within 11% if
* <code>desiredCapacity &gt;= 1000</code>).
*
* @param desiredCapacity the capacity desired by the user.
* @return the capacity which should be used for a hashtable.
*/
public static final int nextPrime(int desiredCapacity) {
int i = Arrays.binarySearch(primeCapacities, desiredCapacity);
if (i<0) {
// desired capacity not found, choose next prime greater
// than desired capacity
i = -i -1; // remember the semantics of binarySearch...
}
return primeCapacities[i];
}
}

View file

@ -0,0 +1,293 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.procedure.TFloatProcedure;
import gnu.trove.impl.HashFunctions;
import gnu.trove.impl.Constants;
import java.util.Arrays;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed hashing implementation for float primitives.
*
* Created: Sun Nov 4 08:56:06 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $
*/
abstract public class TFloatHash extends TPrimitiveHash {
/** the set of floats */
public transient float[] _set;
/**
* value that represents null
*
* NOTE: should not be modified after the Hash is created, but is
* not final because of Externalization
*
*/
protected float no_entry_value;
/**
* Creates a new <code>TFloatHash</code> instance with the default
* capacity and load factor.
*/
public TFloatHash() {
super();
no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( float ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TFloatHash</code> instance whose capacity
* is the next highest prime above <tt>initialCapacity + 1</tt>
* unless that value is already prime.
*
* @param initialCapacity an <code>int</code> value
*/
public TFloatHash( int initialCapacity ) {
super( initialCapacity );
no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( float ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TFloatHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
*/
public TFloatHash( int initialCapacity, float loadFactor ) {
super(initialCapacity, loadFactor);
no_entry_value = Constants.DEFAULT_FLOAT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( float ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TFloatHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
* @param no_entry_value value that represents null
*/
public TFloatHash( int initialCapacity, float loadFactor, float no_entry_value ) {
super(initialCapacity, loadFactor);
this.no_entry_value = no_entry_value;
//noinspection RedundantCast
if ( no_entry_value != ( float ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public float getNoEntryValue() {
return no_entry_value;
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_set = new float[capacity];
return capacity;
}
/**
* Searches the set for <tt>val</tt>
*
* @param val an <code>float</code> value
* @return a <code>boolean</code> value
*/
public boolean contains( float val ) {
return index(val) >= 0;
}
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
public boolean forEach( TFloatProcedure procedure ) {
byte[] states = _states;
float[] set = _set;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ! procedure.execute( set[i] ) ) {
return false;
}
}
return true;
}
/**
* Releases the element currently stored at <tt>index</tt>.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_set[index] = no_entry_value;
super.removeAt( index );
}
/**
* Locates the index of <tt>val</tt>.
*
* @param val an <code>float</code> value
* @return the index of <tt>val</tt> or -1 if it isn't in the set.
*/
protected int index( float val ) {
int hash, probe, index, length;
final byte[] states = _states;
final float[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
// see Knuth, p. 529
probe = 1 + ( hash % ( length - 2 ) );
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
} while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) );
}
return states[index] == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>val</tt> can be inserted. if
* there is already a value equal()ing <tt>val</tt> in the set,
* returns that value as a negative integer.
*
* @param val an <code>float</code> value
* @return an <code>int</code> value
*/
protected int insertionIndex( float val ) {
int hash, probe, index, length;
final byte[] states = _states;
final float[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] == FREE ) {
return index; // empty, all done
} else if ( states[index] == FULL && set[index] == val ) {
return -index -1; // already stored
} else { // already FULL or REMOVED, must probe
// compute the double hash
probe = 1 + ( hash % ( length - 2 ) );
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if ( states[index] != REMOVED ) {
// starting at the natural offset, probe until we find an
// offset that isn't full.
do {
index -= probe;
if (index < 0) {
index += length;
}
} while ( states[index] == FULL && set[index] != val );
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if ( states[index] == REMOVED) {
int firstRemoved = index;
while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
index -= probe;
if (index < 0) {
index += length;
}
}
return states[index] == FULL ? -index -1 : firstRemoved;
}
// if it's full, the key is already stored
return states[index] == FULL ? -index -1 : index;
}
}
} // TFloatHash

View file

@ -0,0 +1,428 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.impl.Constants;
import gnu.trove.impl.HashFunctions;
import gnu.trove.impl.PrimeFinder;
import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.IOException;
import java.io.ObjectInput;
/**
* Base class for hashtables that use open addressing to resolve
* collisions.
*
* Created: Wed Nov 28 21:11:16 2001
*
* @author Eric D. Friedman
* @author Rob Eden (auto-compaction)
* @author Jeff Randall
*
* @version $Id: THash.java,v 1.1.2.4 2010/03/02 00:55:34 robeden Exp $
*/
abstract public class THash implements Externalizable {
static final long serialVersionUID = -1792948471915530295L;
/** the load above which rehashing occurs. */
protected static final float DEFAULT_LOAD_FACTOR = Constants.DEFAULT_LOAD_FACTOR;
/**
* the default initial capacity for the hash table. This is one
* less than a prime value because one is added to it when
* searching for a prime capacity to account for the free slot
* required by open addressing. Thus, the real default capacity is
* 11.
*/
protected static final int DEFAULT_CAPACITY = Constants.DEFAULT_CAPACITY;
/** the current number of occupied slots in the hash. */
protected transient int _size;
/** the current number of free slots in the hash. */
protected transient int _free;
/**
* Determines how full the internal table can become before
* rehashing is required. This must be a value in the range: 0.0 <
* loadFactor < 1.0. The default value is 0.5, which is about as
* large as you can get in open addressing without hurting
* performance. Cf. Knuth, Volume 3., Chapter 6.
*/
protected float _loadFactor;
/**
* The maximum number of elements allowed without allocating more
* space.
*/
protected int _maxSize;
/** The number of removes that should be performed before an auto-compaction occurs. */
protected int _autoCompactRemovesRemaining;
/**
* The auto-compaction factor for the table.
*
* @see #setAutoCompactionFactor
*/
protected float _autoCompactionFactor;
/** @see #tempDisableAutoCompaction */
protected transient boolean _autoCompactTemporaryDisable = false;
/**
* Creates a new <code>THash</code> instance with the default
* capacity and load factor.
*/
public THash() {
this( DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR );
}
/**
* Creates a new <code>THash</code> instance with a prime capacity
* at or near the specified capacity and with the default load
* factor.
*
* @param initialCapacity an <code>int</code> value
*/
public THash( int initialCapacity ) {
this( initialCapacity, DEFAULT_LOAD_FACTOR );
}
/**
* Creates a new <code>THash</code> instance with a prime capacity
* at or near the minimum needed to hold <tt>initialCapacity</tt>
* elements with load factor <tt>loadFactor</tt> without triggering
* a rehash.
*
* @param initialCapacity an <code>int</code> value
* @param loadFactor a <code>float</code> value
*/
public THash( int initialCapacity, float loadFactor ) {
super();
_loadFactor = loadFactor;
// Through testing, the load factor (especially the default load factor) has been
// found to be a pretty good starting auto-compaction factor.
_autoCompactionFactor = loadFactor;
setUp( HashFunctions.fastCeil( initialCapacity / loadFactor ) );
}
/**
* Tells whether this set is currently holding any elements.
*
* @return a <code>boolean</code> value
*/
public boolean isEmpty() {
return 0 == _size;
}
/**
* Returns the number of distinct elements in this collection.
*
* @return an <code>int</code> value
*/
public int size() {
return _size;
}
/** @return the current physical capacity of the hash table. */
abstract public int capacity();
/**
* Ensure that this hashtable has sufficient capacity to hold
* <tt>desiredCapacity<tt> <b>additional</b> elements without
* requiring a rehash. This is a tuning method you can call
* before doing a large insert.
*
* @param desiredCapacity an <code>int</code> value
*/
public void ensureCapacity( int desiredCapacity ) {
if ( desiredCapacity > ( _maxSize - size() ) ) {
rehash( PrimeFinder.nextPrime( HashFunctions.fastCeil(
( desiredCapacity + size() ) / _loadFactor ) + 1 ) );
computeMaxSize( capacity() );
}
}
/**
* Compresses the hashtable to the minimum prime size (as defined
* by PrimeFinder) that will hold all of the elements currently in
* the table. If you have done a lot of <tt>remove</tt>
* operations and plan to do a lot of queries or insertions or
* iteration, it is a good idea to invoke this method. Doing so
* will accomplish two things:
* <p/>
* <ol>
* <li> You'll free memory allocated to the table but no
* longer needed because of the remove()s.</li>
* <p/>
* <li> You'll get better query/insert/iterator performance
* because there won't be any <tt>REMOVED</tt> slots to skip
* over when probing for indices in the table.</li>
* </ol>
*/
public void compact() {
// need at least one free spot for open addressing
rehash( PrimeFinder.nextPrime( HashFunctions.fastCeil( size() / _loadFactor ) + 1 ) );
computeMaxSize( capacity() );
// If auto-compaction is enabled, re-determine the compaction interval
if ( _autoCompactionFactor != 0 ) {
computeNextAutoCompactionAmount( size() );
}
}
/**
* The auto-compaction factor controls whether and when a table performs a
* {@link #compact} automatically after a certain number of remove operations.
* If the value is non-zero, the number of removes that need to occur for
* auto-compaction is the size of table at the time of the previous compaction
* (or the initial capacity) multiplied by this factor.
* <p/>
* Setting this value to zero will disable auto-compaction.
*
* @param factor a <tt>float</tt> that indicates the auto-compaction factor
*/
public void setAutoCompactionFactor( float factor ) {
if ( factor < 0 ) {
throw new IllegalArgumentException( "Factor must be >= 0: " + factor );
}
_autoCompactionFactor = factor;
}
/**
* @see #setAutoCompactionFactor
*
* @return a <<tt>float</tt> that represents the auto-compaction factor.
*/
public float getAutoCompactionFactor() {
return _autoCompactionFactor;
}
/**
* This simply calls {@link #compact compact}. It is included for
* symmetry with other collection classes. Note that the name of this
* method is somewhat misleading (which is why we prefer
* <tt>compact</tt>) as the load factor may require capacity above
* and beyond the size of this collection.
*
* @see #compact
*/
public final void trimToSize() {
compact();
}
/**
* Delete the record at <tt>index</tt>. Reduces the size of the
* collection by one.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_size--;
// If auto-compaction is enabled, see if we need to compact
if ( _autoCompactionFactor != 0 ) {
_autoCompactRemovesRemaining--;
if ( !_autoCompactTemporaryDisable && _autoCompactRemovesRemaining <= 0 ) {
// Do the compact
// NOTE: this will cause the next compaction interval to be calculated
compact();
}
}
}
/** Empties the collection. */
public void clear() {
_size = 0;
_free = capacity();
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = PrimeFinder.nextPrime( initialCapacity );
computeMaxSize( capacity );
computeNextAutoCompactionAmount( initialCapacity );
return capacity;
}
/**
* Rehashes the set.
*
* @param newCapacity an <code>int</code> value
*/
protected abstract void rehash( int newCapacity );
/**
* Temporarily disables auto-compaction. MUST be followed by calling
* {@link #reenableAutoCompaction}.
*/
public void tempDisableAutoCompaction() {
_autoCompactTemporaryDisable = true;
}
/**
* Re-enable auto-compaction after it was disabled via
* {@link #tempDisableAutoCompaction()}.
*
* @param check_for_compaction True if compaction should be performed if needed
* before returning. If false, no compaction will be
* performed.
*/
public void reenableAutoCompaction( boolean check_for_compaction ) {
_autoCompactTemporaryDisable = false;
if ( check_for_compaction && _autoCompactRemovesRemaining <= 0 &&
_autoCompactionFactor != 0 ) {
// Do the compact
// NOTE: this will cause the next compaction interval to be calculated
compact();
}
}
/**
* Computes the values of maxSize. There will always be at least
* one free slot required.
*
* @param capacity an <code>int</code> value
*/
protected void computeMaxSize( int capacity ) {
// need at least one free slot for open addressing
_maxSize = Math.min( capacity - 1, (int) ( capacity * _loadFactor ) );
_free = capacity - _size; // reset the free element count
}
/**
* Computes the number of removes that need to happen before the next auto-compaction
* will occur.
*
* @param size an <tt>int</tt> that sets the auto-compaction limit.
*/
protected void computeNextAutoCompactionAmount( int size ) {
if ( _autoCompactionFactor != 0 ) {
// NOTE: doing the round ourselves has been found to be faster than using
// Math.round.
_autoCompactRemovesRemaining =
(int) ( ( size * _autoCompactionFactor ) + 0.5f );
}
}
/**
* After an insert, this hook is called to adjust the size/free
* values of the set and to perform rehashing if necessary.
*
* @param usedFreeSlot the slot
*/
protected final void postInsertHook( boolean usedFreeSlot ) {
if ( usedFreeSlot ) {
_free--;
}
// rehash whenever we exhaust the available space in the table
if ( ++_size > _maxSize || _free == 0 ) {
// choose a new capacity suited to the new state of the table
// if we've grown beyond our maximum size, double capacity;
// if we've exhausted the free spots, rehash to the same capacity,
// which will free up any stale removed slots for reuse.
int newCapacity = _size > _maxSize ? PrimeFinder.nextPrime( capacity() << 1 ) : capacity();
rehash( newCapacity );
computeMaxSize( capacity() );
}
}
protected int calculateGrownCapacity() {
return capacity() << 1;
}
public void writeExternal( ObjectOutput out ) throws IOException {
// VERSION
out.writeByte( 0 );
// LOAD FACTOR
out.writeFloat( _loadFactor );
// AUTO COMPACTION LOAD FACTOR
out.writeFloat( _autoCompactionFactor );
}
public void readExternal( ObjectInput in )
throws IOException, ClassNotFoundException {
// VERSION
in.readByte();
// LOAD FACTOR
float old_factor = _loadFactor;
_loadFactor = in.readFloat();
// AUTO COMPACTION LOAD FACTOR
_autoCompactionFactor = in.readFloat();
// If we change the laod factor from the default, re-setup
if ( old_factor != _loadFactor ) {
setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) );
}
}
}// THash

View file

@ -0,0 +1,177 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.iterator.TIterator;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Implements all iterator functions for the hashed object set.
* Subclasses may override objectAtIndex to vary the object
* returned by calls to next() (e.g. for values, and Map.Entry
* objects).
* <p/>
* <p> Note that iteration is fastest if you forego the calls to
* <tt>hasNext</tt> in favor of checking the size of the structure
* yourself and then call next() that many times:
* <p/>
* <pre>
* Iterator i = collection.iterator();
* for (int size = collection.size(); size-- > 0;) {
* Object o = i.next();
* }
* </pre>
* <p/>
* <p>You may, of course, use the hasNext(), next() idiom too if
* you aren't in a performance critical spot.</p>
*/
public abstract class THashIterator<V> implements TIterator, Iterator<V> {
private final TObjectHash<V> _object_hash;
/** the data structure this iterator traverses */
protected final THash _hash;
/**
* the number of elements this iterator believes are in the
* data structure it accesses.
*/
protected int _expectedSize;
/** the index used for iteration. */
protected int _index;
/**
* Create an instance of THashIterator over the values of the TObjectHash
*
* @param hash the object
*/
protected THashIterator( TObjectHash<V> hash ) {
_hash = hash;
_expectedSize = _hash.size();
_index = _hash.capacity();
_object_hash = hash;
}
/**
* Moves the iterator to the next Object and returns it.
*
* @return an <code>Object</code> value
* @throws ConcurrentModificationException
* if the structure
* was changed using a method that isn't on this iterator.
* @throws NoSuchElementException if this is called on an
* exhausted iterator.
*/
public V next() {
moveToNextIndex();
return objectAtIndex( _index );
}
/**
* Returns true if the iterator can be advanced past its current
* location.
*
* @return a <code>boolean</code> value
*/
public boolean hasNext() {
return nextIndex() >= 0;
}
/**
* Removes the last entry returned by the iterator.
* Invoking this method more than once for a single entry
* will leave the underlying data structure in a confused
* state.
*/
public void remove() {
if ( _expectedSize != _hash.size() ) {
throw new ConcurrentModificationException();
}
// Disable auto compaction during the remove. This is a workaround for bug 1642768.
try {
_hash.tempDisableAutoCompaction();
_hash.removeAt( _index );
}
finally {
_hash.reenableAutoCompaction( false );
}
_expectedSize--;
}
/**
* Sets the internal <tt>index</tt> so that the `next' object
* can be returned.
*/
protected final void moveToNextIndex() {
// doing the assignment && < 0 in one line shaves
// 3 opcodes...
if ( ( _index = nextIndex() ) < 0 ) {
throw new NoSuchElementException();
}
}
/**
* Returns the index of the next value in the data structure
* or a negative value if the iterator is exhausted.
*
* @return an <code>int</code> value
* @throws ConcurrentModificationException
* if the underlying
* collection's size has been modified since the iterator was
* created.
*/
protected final int nextIndex() {
if ( _expectedSize != _hash.size() ) {
throw new ConcurrentModificationException();
}
Object[] set = _object_hash._set;
int i = _index;
while ( i-- > 0 && ( set[i] == TObjectHash.FREE || set[i] == TObjectHash.REMOVED ) ) {
;
}
return i;
}
/**
* Returns the object at the specified index. Subclasses should
* implement this to return the appropriate object for the given
* index.
*
* @param index the index of the value to return.
* @return an <code>Object</code> value
*/
abstract protected V objectAtIndex( int index );
} // THashIterator

View file

@ -0,0 +1,143 @@
// ////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// ////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.iterator.TPrimitiveIterator;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
/**
* Implements all iterator functions for the hashed object set.
* Subclasses may override objectAtIndex to vary the object
* returned by calls to next() (e.g. for values, and Map.Entry
* objects).
* <p/>
* <p> Note that iteration is fastest if you forego the calls to
* <tt>hasNext</tt> in favor of checking the size of the structure
* yourself and then call next() that many times:
* <p/>
* <pre>
* Iterator i = collection.iterator();
* for (int size = collection.size(); size-- > 0;) {
* Object o = i.next();
* }
* </pre>
* <p/>
* <p>You may, of course, use the hasNext(), next() idiom too if
* you aren't in a performance critical spot.</p>
*/
public abstract class THashPrimitiveIterator implements TPrimitiveIterator {
/** the data structure this iterator traverses */
protected final TPrimitiveHash _hash;
/**
* the number of elements this iterator believes are in the
* data structure it accesses.
*/
protected int _expectedSize;
/** the index used for iteration. */
protected int _index;
/**
* Creates a <tt>TPrimitiveIterator</tt> for the specified collection.
*
* @param hash the <tt>TPrimitiveHash</tt> we want to iterate over.
*/
public THashPrimitiveIterator( TPrimitiveHash hash ) {
_hash = hash;
_expectedSize = _hash.size();
_index = _hash.capacity();
}
/**
* Returns the index of the next value in the data structure
* or a negative value if the iterator is exhausted.
*
* @return an <code>int</code> value
* @throws java.util.ConcurrentModificationException
* if the underlying collection's
* size has been modified since the iterator was created.
*/
protected final int nextIndex() {
if ( _expectedSize != _hash.size() ) {
throw new ConcurrentModificationException();
}
byte[] states = _hash._states;
int i = _index;
while ( i-- > 0 && ( states[i] != TPrimitiveHash.FULL ) ) {
;
}
return i;
}
/**
* Returns true if the iterator can be advanced past its current
* location.
*
* @return a <code>boolean</code> value
*/
public boolean hasNext() {
return nextIndex() >= 0;
}
/**
* Removes the last entry returned by the iterator.
* Invoking this method more than once for a single entry
* will leave the underlying data structure in a confused
* state.
*/
public void remove() {
if (_expectedSize != _hash.size()) {
throw new ConcurrentModificationException();
}
// Disable auto compaction during the remove. This is a workaround for bug 1642768.
try {
_hash.tempDisableAutoCompaction();
_hash.removeAt(_index);
}
finally {
_hash.reenableAutoCompaction( false );
}
_expectedSize--;
}
/**
* Sets the internal <tt>index</tt> so that the `next' object
* can be returned.
*/
protected final void moveToNextIndex() {
// doing the assignment && < 0 in one line shaves
// 3 opcodes...
if ( ( _index = nextIndex() ) < 0 ) {
throw new NoSuchElementException();
}
}
} // TPrimitiveIterator

View file

@ -0,0 +1,293 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.procedure.TIntProcedure;
import gnu.trove.impl.HashFunctions;
import gnu.trove.impl.Constants;
import java.util.Arrays;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed hashing implementation for int primitives.
*
* Created: Sun Nov 4 08:56:06 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $
*/
abstract public class TIntHash extends TPrimitiveHash {
/** the set of ints */
public transient int[] _set;
/**
* value that represents null
*
* NOTE: should not be modified after the Hash is created, but is
* not final because of Externalization
*
*/
protected int no_entry_value;
/**
* Creates a new <code>TIntHash</code> instance with the default
* capacity and load factor.
*/
public TIntHash() {
super();
no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TIntHash</code> instance whose capacity
* is the next highest prime above <tt>initialCapacity + 1</tt>
* unless that value is already prime.
*
* @param initialCapacity an <code>int</code> value
*/
public TIntHash( int initialCapacity ) {
super( initialCapacity );
no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TIntHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
*/
public TIntHash( int initialCapacity, float loadFactor ) {
super(initialCapacity, loadFactor);
no_entry_value = Constants.DEFAULT_INT_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TIntHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
* @param no_entry_value value that represents null
*/
public TIntHash( int initialCapacity, float loadFactor, int no_entry_value ) {
super(initialCapacity, loadFactor);
this.no_entry_value = no_entry_value;
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public int getNoEntryValue() {
return no_entry_value;
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_set = new int[capacity];
return capacity;
}
/**
* Searches the set for <tt>val</tt>
*
* @param val an <code>int</code> value
* @return a <code>boolean</code> value
*/
public boolean contains( int val ) {
return index(val) >= 0;
}
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
public boolean forEach( TIntProcedure procedure ) {
byte[] states = _states;
int[] set = _set;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ! procedure.execute( set[i] ) ) {
return false;
}
}
return true;
}
/**
* Releases the element currently stored at <tt>index</tt>.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_set[index] = no_entry_value;
super.removeAt( index );
}
/**
* Locates the index of <tt>val</tt>.
*
* @param val an <code>int</code> value
* @return the index of <tt>val</tt> or -1 if it isn't in the set.
*/
protected int index( int val ) {
int hash, probe, index, length;
final byte[] states = _states;
final int[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
// see Knuth, p. 529
probe = 1 + ( hash % ( length - 2 ) );
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
} while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) );
}
return states[index] == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>val</tt> can be inserted. if
* there is already a value equal()ing <tt>val</tt> in the set,
* returns that value as a negative integer.
*
* @param val an <code>int</code> value
* @return an <code>int</code> value
*/
protected int insertionIndex( int val ) {
int hash, probe, index, length;
final byte[] states = _states;
final int[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] == FREE ) {
return index; // empty, all done
} else if ( states[index] == FULL && set[index] == val ) {
return -index -1; // already stored
} else { // already FULL or REMOVED, must probe
// compute the double hash
probe = 1 + ( hash % ( length - 2 ) );
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if ( states[index] != REMOVED ) {
// starting at the natural offset, probe until we find an
// offset that isn't full.
do {
index -= probe;
if (index < 0) {
index += length;
}
} while ( states[index] == FULL && set[index] != val );
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if ( states[index] == REMOVED) {
int firstRemoved = index;
while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
index -= probe;
if (index < 0) {
index += length;
}
}
return states[index] == FULL ? -index -1 : firstRemoved;
}
// if it's full, the key is already stored
return states[index] == FULL ? -index -1 : index;
}
}
} // TIntHash

View file

@ -0,0 +1,293 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.procedure.TLongProcedure;
import gnu.trove.impl.HashFunctions;
import gnu.trove.impl.Constants;
import java.util.Arrays;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed hashing implementation for long primitives.
*
* Created: Sun Nov 4 08:56:06 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Hash.template,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $
*/
abstract public class TLongHash extends TPrimitiveHash {
/** the set of longs */
public transient long[] _set;
/**
* value that represents null
*
* NOTE: should not be modified after the Hash is created, but is
* not final because of Externalization
*
*/
protected long no_entry_value;
/**
* Creates a new <code>TLongHash</code> instance with the default
* capacity and load factor.
*/
public TLongHash() {
super();
no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TLongHash</code> instance whose capacity
* is the next highest prime above <tt>initialCapacity + 1</tt>
* unless that value is already prime.
*
* @param initialCapacity an <code>int</code> value
*/
public TLongHash( int initialCapacity ) {
super( initialCapacity );
no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TLongHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
*/
public TLongHash( int initialCapacity, float loadFactor ) {
super(initialCapacity, loadFactor);
no_entry_value = Constants.DEFAULT_LONG_NO_ENTRY_VALUE;
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TLongHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
* @param no_entry_value value that represents null
*/
public TLongHash( int initialCapacity, float loadFactor, long no_entry_value ) {
super(initialCapacity, loadFactor);
this.no_entry_value = no_entry_value;
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public long getNoEntryValue() {
return no_entry_value;
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_set = new long[capacity];
return capacity;
}
/**
* Searches the set for <tt>val</tt>
*
* @param val an <code>long</code> value
* @return a <code>boolean</code> value
*/
public boolean contains( long val ) {
return index(val) >= 0;
}
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
public boolean forEach( TLongProcedure procedure ) {
byte[] states = _states;
long[] set = _set;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ! procedure.execute( set[i] ) ) {
return false;
}
}
return true;
}
/**
* Releases the element currently stored at <tt>index</tt>.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_set[index] = no_entry_value;
super.removeAt( index );
}
/**
* Locates the index of <tt>val</tt>.
*
* @param val an <code>long</code> value
* @return the index of <tt>val</tt> or -1 if it isn't in the set.
*/
protected int index( long val ) {
int hash, probe, index, length;
final byte[] states = _states;
final long[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
// see Knuth, p. 529
probe = 1 + ( hash % ( length - 2 ) );
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
} while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) );
}
return states[index] == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>val</tt> can be inserted. if
* there is already a value equal()ing <tt>val</tt> in the set,
* returns that value as a negative integer.
*
* @param val an <code>long</code> value
* @return an <code>int</code> value
*/
protected int insertionIndex( long val ) {
int hash, probe, index, length;
final byte[] states = _states;
final long[] set = _set;
length = states.length;
hash = HashFunctions.hash( val ) & 0x7fffffff;
index = hash % length;
if ( states[index] == FREE ) {
return index; // empty, all done
} else if ( states[index] == FULL && set[index] == val ) {
return -index -1; // already stored
} else { // already FULL or REMOVED, must probe
// compute the double hash
probe = 1 + ( hash % ( length - 2 ) );
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if ( states[index] != REMOVED ) {
// starting at the natural offset, probe until we find an
// offset that isn't full.
do {
index -= probe;
if (index < 0) {
index += length;
}
} while ( states[index] == FULL && set[index] != val );
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if ( states[index] == REMOVED) {
int firstRemoved = index;
while ( states[index] != FREE &&
( states[index] == REMOVED || set[index] != val ) ) {
index -= probe;
if (index < 0) {
index += length;
}
}
return states[index] == FULL ? -index -1 : firstRemoved;
}
// if it's full, the key is already stored
return states[index] == FULL ? -index -1 : index;
}
}
} // TLongHash

View file

@ -0,0 +1,312 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.impl.HashFunctions;
import gnu.trove.procedure.TObjectProcedure;
import java.util.Arrays;
import java.io.ObjectOutput;
import java.io.IOException;
import java.io.ObjectInput;
/**
* An open addressed hashing implementation for Object types.
* <p/>
* Created: Sun Nov 4 08:56:06 2001
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: TObjectHash.java,v 1.1.2.6 2009/11/07 03:36:44 robeden Exp $
*/
abstract public class TObjectHash<T> extends THash {
static final long serialVersionUID = -3461112548087185871L;
/** the set of Objects */
public transient Object[] _set;
public static final Object REMOVED = new Object(), FREE = new Object();
/**
* Creates a new <code>TObjectHash</code> instance with the
* default capacity and load factor.
*/
public TObjectHash() {
super();
}
/**
* Creates a new <code>TObjectHash</code> instance whose capacity
* is the next highest prime above <tt>initialCapacity + 1</tt>
* unless that value is already prime.
*
* @param initialCapacity an <code>int</code> value
*/
public TObjectHash( int initialCapacity ) {
super( initialCapacity );
}
/**
* Creates a new <code>TObjectHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param loadFactor used to calculate the threshold over which
* rehashing takes place.
*/
public TObjectHash( int initialCapacity, float loadFactor ) {
super( initialCapacity, loadFactor );
}
public int capacity() {
return _set.length;
}
protected void removeAt( int index ) {
_set[index] = REMOVED;
super.removeAt( index );
}
/**
* initializes the Object set of this hash table.
*
* @param initialCapacity an <code>int</code> value
* @return an <code>int</code> value
*/
public int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_set = new Object[capacity];
Arrays.fill( _set, FREE );
return capacity;
}
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
@SuppressWarnings({"unchecked"})
public boolean forEach( TObjectProcedure<T> procedure ) {
Object[] set = _set;
for ( int i = set.length; i-- > 0; ) {
if ( set[i] != FREE
&& set[i] != REMOVED
&& !procedure.execute( (T) set[i] ) ) {
return false;
}
}
return true;
}
/**
* Searches the set for <tt>obj</tt>
*
* @param obj an <code>Object</code> value
* @return a <code>boolean</code> value
*/
@SuppressWarnings({"unchecked"})
public boolean contains( Object obj ) {
return index( obj ) >= 0;
}
/**
* Locates the index of <tt>obj</tt>.
*
* @param obj an <code>Object</code> value
* @return the index of <tt>obj</tt> or -1 if it isn't in the set.
*/
protected int index( Object obj ) {
final Object[] set = _set;
final int length = set.length;
final int hash = HashFunctions.hash( obj ) & 0x7fffffff;
int index = hash % length;
Object cur = set[index];
if ( cur == obj ) {
return index;
}
if ( cur == FREE ) {
return -1;
}
// NOTE: here it has to be REMOVED or FULL (some user-given value)
if ( cur == REMOVED || !cur.equals( obj ) ) {
// see Knuth, p. 529
final int probe = 1 + ( hash % ( length - 2 ) );
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
cur = set[index];
} while ( cur != FREE
&& ( cur == REMOVED || !cur.equals( obj ) ) );
}
return cur == FREE ? -1 : index;
}
/**
* Locates the index at which <tt>obj</tt> can be inserted. if
* there is already a value equal()ing <tt>obj</tt> in the set,
* returns that value's index as <tt>-index - 1</tt>.
*
* @param obj an <code>Object</code> value
* @return the index of a FREE slot at which obj can be inserted
* or, if obj is already stored in the hash, the negative value of
* that index, minus 1: -index -1.
*/
protected int insertionIndex( T obj ) {
final Object[] set = _set;
final int length = set.length;
final int hash = HashFunctions.hash( obj ) & 0x7fffffff;
int index = hash % length;
Object cur = set[index];
if ( cur == FREE ) {
return index; // empty, all done
} else if ( cur == obj || ( cur != REMOVED && cur.equals( obj ) ) ) {
return -index - 1; // already stored
} else { // already FULL or REMOVED, must probe
// compute the double hash
final int probe = 1 + ( hash % ( length - 2 ) );
// if the slot we landed on is FULL (but not removed), probe
// until we find an empty slot, a REMOVED slot, or an element
// equal to the one we are trying to insert.
// finding an empty slot means that the value is not present
// and that we should use that slot as the insertion point;
// finding a REMOVED slot means that we need to keep searching,
// however we want to remember the offset of that REMOVED slot
// so we can reuse it in case a "new" insertion (i.e. not an update)
// is possible.
// finding a matching value means that we've found that our desired
// key is already in the table
if ( cur != REMOVED ) {
// starting at the natural offset, probe until we find an
// offset that isn't full.
do {
index -= probe;
if ( index < 0 ) {
index += length;
}
cur = set[index];
} while ( cur != FREE
&& cur != REMOVED
&& cur != obj
&& !cur.equals( obj ) );
}
// if the index we found was removed: continue probing until we
// locate a free location or an element which equal()s the
// one we have.
if ( cur == REMOVED ) {
int firstRemoved = index;
while ( cur != FREE
&& ( cur == REMOVED || cur != obj || !cur.equals( obj ) ) ) {
index -= probe;
if ( index < 0 ) {
index += length;
}
cur = set[index];
}
// NOTE: cur cannot == REMOVED in this block
return ( cur != FREE ) ? -index - 1 : firstRemoved;
}
// if it's full, the key is already stored
// NOTE: cur cannot equal REMOVE here (would have retuned already (see above)
return ( cur != FREE ) ? -index - 1 : index;
}
}
/**
* Convenience methods for subclasses to use in throwing exceptions about
* badly behaved user objects employed as keys. We have to throw an
* IllegalArgumentException with a rather verbose message telling the
* user that they need to fix their object implementation to conform
* to the general contract for java.lang.Object.
*
* @param o1 the first of the equal elements with unequal hash codes.
* @param o2 the second of the equal elements with unequal hash codes.
* @throws IllegalArgumentException the whole point of this method.
*/
protected final void throwObjectContractViolation( Object o1, Object o2 )
throws IllegalArgumentException {
throw new IllegalArgumentException( "Equal objects must have equal hashcodes. "
+ "During rehashing, Trove discovered that "
+ "the following two objects claim to be "
+ "equal (as in java.lang.Object.equals()) "
+ "but their hashCodes (or those calculated by "
+ "your TObjectHashingStrategy) are not equal."
+ "This violates the general contract of "
+ "java.lang.Object.hashCode(). See bullet point two "
+ "in that method's documentation. "
+ "object #1 =" + o1
+ "; object #2 =" + o2 );
}
@Override
public void writeExternal( ObjectOutput out ) throws IOException {
// VERSION
out.writeByte( 0 );
// SUPER
super.writeExternal( out );
}
@Override
public void readExternal( ObjectInput in )
throws IOException, ClassNotFoundException {
// VERSION
in.readByte();
// SUPER
super.readExternal( in );
}
} // TObjectHash

View file

@ -0,0 +1,135 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.impl.hash;
import gnu.trove.impl.HashFunctions;
/**
* The base class for hashtables of primitive values. Since there is
* no notion of object equality for primitives, it isn't possible to
* use a `REMOVED' object to track deletions in an open-addressed table.
* So, we have to resort to using a parallel `bookkeeping' array of bytes,
* in which flags can be set to indicate that a particular slot in the
* hash table is FREE, FULL, or REMOVED.
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: TPrimitiveHash.java,v 1.1.2.6 2010/03/01 23:39:07 robeden Exp $
*/
abstract public class TPrimitiveHash extends THash {
/**
* flags indicating whether each position in the hash is
* FREE, FULL, or REMOVED
*/
public transient byte[] _states;
/* constants used for state flags */
/** flag indicating that a slot in the hashtable is available */
public static final byte FREE = 0;
/** flag indicating that a slot in the hashtable is occupied */
public static final byte FULL = 1;
/**
* flag indicating that the value of a slot in the hashtable
* was deleted
*/
public static final byte REMOVED = 2;
/**
* Creates a new <code>THash</code> instance with the default
* capacity and load factor.
*/
public TPrimitiveHash() {
super();
}
/**
* Creates a new <code>TPrimitiveHash</code> instance with a prime
* capacity at or near the specified capacity and with the default
* load factor.
*
* @param initialCapacity an <code>int</code> value
*/
public TPrimitiveHash( int initialCapacity ) {
this( initialCapacity, DEFAULT_LOAD_FACTOR );
}
/**
* Creates a new <code>TPrimitiveHash</code> instance with a prime
* capacity at or near the minimum needed to hold
* <tt>initialCapacity<tt> elements with load factor
* <tt>loadFactor</tt> without triggering a rehash.
*
* @param initialCapacity an <code>int</code> value
* @param loadFactor a <code>float</code> value
*/
public TPrimitiveHash( int initialCapacity, float loadFactor ) {
super();
initialCapacity = Math.max( 1, initialCapacity );
_loadFactor = loadFactor;
setUp( HashFunctions.fastCeil( initialCapacity / loadFactor ) );
}
/**
* Returns the capacity of the hash table. This is the true
* physical capacity, without adjusting for the load factor.
*
* @return the physical capacity of the hash table.
*/
public int capacity() {
return _states.length;
}
/**
* Delete the record at <tt>index</tt>.
*
* @param index an <code>int</code> value
*/
protected void removeAt( int index ) {
_states[index] = REMOVED;
super.removeAt( index );
}
/**
* initializes the hashtable to a prime capacity which is at least
* <tt>initialCapacity + 1</tt>.
*
* @param initialCapacity an <code>int</code> value
* @return the actual capacity chosen
*/
protected int setUp( int initialCapacity ) {
int capacity;
capacity = super.setUp( initialCapacity );
_states = new byte[capacity];
return capacity;
}
} // TPrimitiveHash

View file

@ -0,0 +1,31 @@
// ////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// ////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
/**
* Common interface for iterators that operate via the "advance" method for moving the
* cursor to the next element.
*/
public interface TAdvancingIterator extends TIterator {
/**
* Moves the iterator forward to the next entry.
*
* @throws java.util.NoSuchElementException if the iterator is already exhausted
*/
public void advance();
}

View file

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Iterator for float collections.
*/
public interface TFloatIterator extends TIterator {
/**
* Advances the iterator to the next element in the underlying collection
* and returns it.
*
* @return the next float in the collection
* @exception NoSuchElementException if the iterator is already exhausted
*/
public float next();
}

View file

@ -0,0 +1,125 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Iterator for maps of type float and Object.
* <p/>
* The iterator semantics for Trove's primitive maps is slightly different
* from those defined in <tt>java.util.Iterator</tt>, but still well within
* the scope of the pattern, as defined by Gamma, et al.
* <p/>
* This iterator does <b>not</b> implicitly advance to the next entry when
* the value at the current position is retrieved. Rather, you must explicitly
* ask the iterator to <tt>advance()</tt> and then retrieve either the <tt>key()</tt>,
* the <tt>value()</tt> or both. This is done so that you have the option, but not
* the obligation, to retrieve keys and/or values as your application requires, and
* without introducing wrapper objects that would carry both. As the iteration is
* stateful, access to the key/value parts of the current map entry happens in
* constant time.
* <p/>
* In practice, the iterator is akin to a "search finger" that you move from
* position to position. Read or write operations affect the current entry only and
* do not assume responsibility for moving the finger.
* <p/>
* Here are some sample scenarios for this class of iterator:
* <p/>
* <pre>
* // accessing keys/values through an iterator:
* for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) ) {
* doSomethingWithValue( it.value() );
* }
* }
* </pre>
* <p/>
* <pre>
* // modifying values in-place through iteration:
* for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) ) {
* it.setValue( newValueForKey( it.key() ) );
* }
* }
* </pre>
* <p/>
* <pre>
* // deleting entries during iteration:
* for ( TFloatObjectIterator it = map.iterator(); it.hasNext(); ) {
* it.advance();
* if ( satisfiesCondition( it.key() ) ) {
* it.remove();
* }
* }
* </pre>
* <p/>
* <pre>
* // faster iteration by avoiding hasNext():
* TFloatObjectIterator iterator = map.iterator();
* for ( int i = map.size(); i-- > 0; ) {
* iterator.advance();
* doSomethingWithKeyAndValue( iterator.key(), iterator.value() );
* }
* </pre>
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
* @version $Id: _E_ObjectIterator.template,v 1.1.2.1 2009/09/15 02:38:31 upholderoftruth Exp $
*/
public interface TFloatObjectIterator<V> extends TAdvancingIterator {
/**
* Provides access to the key of the mapping at the iterator's position.
* Note that you must <tt>advance()</tt> the iterator at least once
* before invoking this method.
*
* @return the key of the entry at the iterator's current position.
*/
public float key();
/**
* Provides access to the value of the mapping at the iterator's position.
* Note that you must <tt>advance()</tt> the iterator at least once
* before invoking this method.
*
* @return the value of the entry at the iterator's current position.
*/
public V value();
/**
* Replace the value of the mapping at the iterator's position with the
* specified value. Note that you must <tt>advance()</tt> the iterator at
* least once before invoking this method.
*
* @param val the value to set in the current entry
* @return the old value of the entry.
*/
public V setValue( V val );
}

View file

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Iterator for int collections.
*/
public interface TIntIterator extends TIterator {
/**
* Advances the iterator to the next element in the underlying collection
* and returns it.
*
* @return the next int in the collection
* @exception NoSuchElementException if the iterator is already exhausted
*/
public int next();
}

View file

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
/**
* Common interface for all iterators used in Trove.
*/
public interface TIterator {
/**
* Returns true if the iterator can be advanced past its current location.
*
* @return a <code>boolean</code> value
*/
public boolean hasNext();
/**
* Removes the last entry returned by the iterator. The result of invoking this method
* more than once for a single entry is undefined and can leave the underlying data
* structure in a confused state.
*/
public void remove();
}

View file

@ -0,0 +1,38 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Iterator for long collections.
*/
public interface TLongIterator extends TIterator {
/**
* Advances the iterator to the next element in the underlying collection
* and returns it.
*
* @return the next long in the collection
* @exception NoSuchElementException if the iterator is already exhausted
*/
public long next();
}

View file

@ -0,0 +1,61 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.iterator;
/**
* Implements all iterator functions for the hashed object set.
* Subclasses may override objectAtIndex to vary the object
* returned by calls to next() (e.g. for values, and Map.Entry
* objects).
* <p/>
* <p> Note that iteration is fastest if you forego the calls to
* <tt>hasNext</tt> in favor of checking the size of the structure
* yourself and then call next() that many times:
* <p/>
* <pre>
* Iterator i = collection.iterator();
* for (int size = collection.size(); size-- > 0;) {
* Object o = i.next();
* }
* </pre>
* <p/>
* <p>You may, of course, use the hasNext(), next() idiom too if
* you aren't in a performance critical spot.</p>
*/
public interface TPrimitiveIterator extends TIterator {
/**
* Returns true if the iterator can be advanced past its current
* location.
*
* @return a <code>boolean</code> value
*/
public boolean hasNext();
/**
* Removes the last entry returned by the iterator.
* Invoking this method more than once for a single entry
* will leave the underlying data structure in a confused
* state.
*/
public void remove();
} // TPrimitiveIterator

View file

@ -0,0 +1,508 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.list;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.function.*;
import gnu.trove.procedure.*;
import gnu.trove.TIntCollection;
import java.io.Serializable;
import java.util.Random;
/**
* Interface for Trove list implementations.
*/
public interface TIntList extends TIntCollection, Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
public int getNoEntryValue();
/**
* Returns the number of values in the list.
*
* @return the number of values in the list.
*/
public int size();
/**
* Tests whether this list contains any values.
*
* @return true if the list is empty.
*/
public boolean isEmpty();
/**
* Adds <tt>val</tt> to the end of the list, growing as needed.
*
* @param val an <code>int</code> value
* @return true if the list was modified by the add operation
*/
public boolean add(int val);
/**
* Adds the values in the array <tt>vals</tt> to the end of the
* list, in order.
*
* @param vals an <code>int[]</code> value
*/
public void add( int[] vals );
/**
* Adds a subset of the values in the array <tt>vals</tt> to the
* end of the list, in order.
*
* @param vals an <code>int[]</code> value
* @param offset the offset at which to start copying
* @param length the number of values to copy.
*/
public void add( int[] vals, int offset, int length );
/**
* Inserts <tt>value</tt> into the list at <tt>offset</tt>. All
* values including and to the right of <tt>offset</tt> are shifted
* to the right.
*
* @param offset an <code>int</code> value
* @param value an <code>int</code> value
*/
public void insert( int offset, int value );
/**
* Inserts the array of <tt>values</tt> into the list at
* <tt>offset</tt>. All values including and to the right of
* <tt>offset</tt> are shifted to the right.
*
* @param offset an <code>int</code> value
* @param values an <code>int[]</code> value
*/
public void insert( int offset, int[] values );
/**
* Inserts a slice of the array of <tt>values</tt> into the list
* at <tt>offset</tt>. All values including and to the right of
* <tt>offset</tt> are shifted to the right.
*
* @param offset an <code>int</code> value
* @param values an <code>int[]</code> value
* @param valOffset the offset in the values array at which to
* start copying.
* @param len the number of values to copy from the values array
*/
public void insert( int offset, int[] values, int valOffset, int len );
/**
* Returns the value at the specified offset.
*
* @param offset an <code>int</code> value
* @return an <code>int</code> value
*/
public int get( int offset );
/**
* Sets the value at the specified offset.
*
* @param offset an <code>int</code> value
* @param val an <code>int</code> value
*
* @return The value previously at the given index.
*/
public int set( int offset, int val );
/**
* Replace the values in the list starting at <tt>offset</tt> with
* the contents of the <tt>values</tt> array.
*
* @param offset the first offset to replace
* @param values the source of the new values
*/
public void set( int offset, int[] values );
/**
* Replace the values in the list starting at <tt>offset</tt> with
* <tt>length</tt> values from the <tt>values</tt> array, starting
* at valOffset.
*
* @param offset the first offset to replace
* @param values the source of the new values
* @param valOffset the first value to copy from the values array
* @param length the number of values to copy
*/
public void set( int offset, int[] values, int valOffset, int length );
/**
* Sets the value at the specified offset and returns the
* previously stored value.
*
* @param offset an <code>int</code> value
* @param val an <code>int</code> value
* @return the value previously stored at offset.
*/
public int replace( int offset, int val );
/**
* Flushes the internal state of the list, resetting the capacity
* to the default.
*/
public void clear();
/**
* Removes <tt>value</tt> from the list.
*
* @param value an <code>int</code> value
* @return true if the list was modified by the remove operation.
*/
public boolean remove( int value );
/**
* Removes <tt>value</tt> at a given offset from the list.
*
* @param offset an <code>int</code> value that represents
* the offset to the element to be removed
* @return an <tt>int</tt> that is the value removed.
*/
public int removeAt( int offset );
/**
* Removes <tt>length</tt> values from the list, starting at
* <tt>offset</tt>
*
* @param offset an <code>int</code> value
* @param length an <code>int</code> value
*/
public void remove( int offset, int length );
/**
* Transform each value in the list using the specified function.
*
* @param function a <code>TIntFunction</code> value
*/
public void transformValues( TIntFunction function );
/**
* Reverse the order of the elements in the list.
*/
public void reverse();
/**
* Reverse the order of the elements in the range of the list.
*
* @param from the inclusive index at which to start reversing
* @param to the exclusive index at which to stop reversing
*/
public void reverse( int from, int to );
/**
* Shuffle the elements of the list using the specified random
* number generator.
*
* @param rand a <code>Random</code> value
*/
public void shuffle( Random rand );
/**
* Returns a sublist of this list.
*
* @param begin low endpoint (inclusive) of the subList.
* @param end high endpoint (exclusive) of the subList.
* @return sublist of this list from begin, inclusive to end, exclusive.
* @throws IndexOutOfBoundsException - endpoint out of range
* @throws IllegalArgumentException - endpoints out of order (end > begin)
*/
public TIntList subList( int begin, int end );
/**
* Copies the contents of the list into a native array.
*
* @return an <code>int[]</code> value
*/
public int[] toArray();
/**
* Copies a slice of the list into a native array.
*
* @param offset the offset at which to start copying
* @param len the number of values to copy.
* @return an <code>int[]</code> value
*/
public int[] toArray( int offset, int len );
/**
* Copies a slice of the list into a native array.
*
* <p>If the list fits in the specified array with room to spare (i.e.,
* the array has more elements than the list), the element in the array
* immediately following the end of the list is set to
* <tt>{@link #getNoEntryValue()}</tt>.
* (This is useful in determining the length of the list <i>only</i> if
* the caller knows that the list does not contain any "null" elements.)
*
* <p>NOTE: Trove does not allocate a new array if the array passed in is
* not large enough to hold all of the data elements. It will instead fill
* the array passed in.
*
* @param dest the array to copy into.
* @return the array passed in.
*/
public int[] toArray( int[] dest );
/**
* Copies a slice of the list into a native array.
*
* @param dest the array to copy into.
* @param offset the offset where the first value should be copied
* @param len the number of values to copy.
* @return the array passed in.
*/
public int[] toArray( int[] dest, int offset, int len );
/**
* Copies a slice of the list into a native array.
*
* @param dest the array to copy into.
* @param source_pos the offset of the first value to copy
* @param dest_pos the offset where the first value should be copied
* @param len the number of values to copy.
* @return the array passed in.
*/
public int[] toArray( int[] dest, int source_pos, int dest_pos, int len );
/**
* Applies the procedure to each value in the list in ascending
* (front to back) order.
*
* @param procedure a <code>TIntProcedure</code> value
* @return true if the procedure did not terminate prematurely.
*/
public boolean forEach( TIntProcedure procedure );
/**
* Applies the procedure to each value in the list in descending
* (back to front) order.
*
* @param procedure a <code>TIntProcedure</code> value
* @return true if the procedure did not terminate prematurely.
*/
public boolean forEachDescending( TIntProcedure procedure );
/**
* Sort the values in the list (ascending) using the Sun quicksort
* implementation.
*
* @see java.util.Arrays#sort
*/
public void sort();
/**
* Sort a slice of the list (ascending) using the Sun quicksort
* implementation.
*
* @param fromIndex the index at which to start sorting (inclusive)
* @param toIndex the index at which to stop sorting (exclusive)
* @see java.util.Arrays#sort
*/
public void sort( int fromIndex, int toIndex );
/**
* Fills every slot in the list with the specified value.
*
* @param val the value to use when filling
*/
public void fill( int val );
/**
* Fills a range in the list with the specified value.
*
* @param fromIndex the offset at which to start filling (inclusive)
* @param toIndex the offset at which to stop filling (exclusive)
* @param val the value to use when filling
*/
public void fill( int fromIndex, int toIndex, int val );
/**
* Performs a binary search for <tt>value</tt> in the entire list.
* Note that you <b>must</b> @{link #sort sort} the list before
* doing a search.
*
* @param value the value to search for
* @return the absolute offset in the list of the value, or its
* negative insertion point into the sorted list.
*/
public int binarySearch( int value );
/**
* Performs a binary search for <tt>value</tt> in the specified
* range. Note that you <b>must</b> @{link #sort sort} the list
* or the range before doing a search.
*
* @param value the value to search for
* @param fromIndex the lower boundary of the range (inclusive)
* @param toIndex the upper boundary of the range (exclusive)
* @return the absolute offset in the list of the value, or its
* negative insertion point into the sorted list.
*/
public int binarySearch( int value, int fromIndex, int toIndex );
/**
* Searches the list front to back for the index of
* <tt>value</tt>.
*
* @param value an <code>int</code> value
* @return the first offset of the value, or -1 if it is not in
* the list.
* @see #binarySearch for faster searches on sorted lists
*/
public int indexOf( int value );
/**
* Searches the list front to back for the index of
* <tt>value</tt>, starting at <tt>offset</tt>.
*
* @param offset the offset at which to start the linear search
* (inclusive)
* @param value an <code>int</code> value
* @return the first offset of the value, or -1 if it is not in
* the list.
* @see #binarySearch for faster searches on sorted lists
*/
public int indexOf( int offset, int value );
/**
* Searches the list back to front for the last index of
* <tt>value</tt>.
*
* @param value an <code>int</code> value
* @return the last offset of the value, or -1 if it is not in
* the list.
* @see #binarySearch for faster searches on sorted lists
*/
public int lastIndexOf( int value );
/**
* Searches the list back to front for the last index of
* <tt>value</tt>, starting at <tt>offset</tt>.
*
* @param offset the offset at which to start the linear search
* (exclusive)
* @param value an <code>int</code> value
* @return the last offset of the value, or -1 if it is not in
* the list.
* @see #binarySearch for faster searches on sorted lists
*/
public int lastIndexOf( int offset, int value );
/**
* Searches the list for <tt>value</tt>
*
* @param value an <code>int</code> value
* @return true if value is in the list.
*/
public boolean contains( int value );
/**
* Searches the list for values satisfying <tt>condition</tt> in
* the manner of the *nix <tt>grep</tt> utility.
*
* @param condition a condition to apply to each element in the list
* @return a list of values which match the condition.
*/
public TIntList grep( TIntProcedure condition );
/**
* Searches the list for values which do <b>not</b> satisfy
* <tt>condition</tt>. This is akin to *nix <code>grep -v</code>.
*
* @param condition a condition to apply to each element in the list
* @return a list of values which do not match the condition.
*/
public TIntList inverseGrep( TIntProcedure condition );
/**
* Finds the maximum value in the list.
*
* @return the largest value in the list.
* @exception IllegalStateException if the list is empty
*/
public int max();
/**
* Finds the minimum value in the list.
*
* @return the smallest value in the list.
* @exception IllegalStateException if the list is empty
*/
public int min();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,425 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.map;
import gnu.trove.iterator.TFloatObjectIterator;
import gnu.trove.procedure.TFloatProcedure;
import gnu.trove.procedure.TObjectProcedure;
import gnu.trove.procedure.TFloatObjectProcedure;
import gnu.trove.function.TObjectFunction;
import gnu.trove.set.TFloatSet;
import java.util.Collection;
import java.util.Map;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for a primitive map of float keys and Object values.
*/
public interface TFloatObjectMap<V> {
// Query Operations
/**
* Returns the value that represents null in the {@link #keySet()}.
* The default value is generally zero, but can be changed during
* construction of the collection.
*
* @return the value that represents a null value in this collection.
*/
float getNoEntryKey();
/**
* Returns the number of key-value mappings in this map. If the
* map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of key-value mappings in this map
*/
int size();
/**
* Returns <tt>true</tt> if this map contains no key-value mappings.
*
* @return <tt>true</tt> if this map contains no key-value mappings
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this map contains a mapping for the specified
* key. More formally, returns <tt>true</tt> if and only if
* this map contains a mapping for a key <tt>k</tt> such that
* <tt>key.equals(k)</tt>. (There can be at most one such mapping.)
*
* @param key key whose presence in this map is to be tested
* @return <tt>true</tt> if this map contains a mapping for the specified
* key
* @throws ClassCastException if the key is of an inappropriate type for
* this map (optional)
* @throws NullPointerException if the specified key is null and this map
* does not permit null keys (optional)
*/
boolean containsKey( float key );
/**
* Returns <tt>true</tt> if this map maps one or more keys to the
* specified value. More formally, returns <tt>true</tt> if and only if
* this map contains at least one mapping to a value <tt>v</tt> such that
* <tt>(value==null ? v==null : value.equals(v))</tt>. This operation
* will probably require time linear in the map size for most
* implementations of the <tt>Map</tt> interface.
*
* @param value value whose presence in this map is to be tested
* @return <tt>true</tt> if this map maps one or more keys to the
* specified value
* @throws ClassCastException if the value is of an inappropriate type for
* this map (optional)
* @throws NullPointerException if the specified value is null and this
* map does not permit null values (optional)
*/
boolean containsValue( Object value );
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
*
* <p>More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (key==null ? k==null :
* key.equals(k))}, then this method returns {@code v}; otherwise
* it returns {@code null}. (There can be at most one such mapping.)
*
* <p>If this map permits null values, then a return value of
* {@code null} does not <i>necessarily</i> indicate that the map
* contains no mapping for the key; it's also possible that the map
* explicitly maps the key to {@code null}. The {@link #containsKey
* containsKey} operation may be used to distinguish these two cases.
*
* @param key the key whose associated value is to be returned
* @return the <tt>float</tt> value to which the specified key is mapped, or
* {@code null} if this map contains no mapping for the key
* @throws ClassCastException if the key is of an inappropriate type for
* this map (optional)
* @throws NullPointerException if the specified key is null and this map
* does not permit null keys (optional)
*/
V get( float key );
// Modification Operations
/**
* Associates the specified value with the specified key in this map
* (optional operation). If the map previously contained a mapping for
* the key, the old value is replaced by the specified value. (A map
* <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only
* if {@link #containsKey(float) m.containsKey(k)} would return
* <tt>true</tt>.)
*
* @param key key with which the specified value is to be associated
* @param value an <tt>float</tt> value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>no_entry_value</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>no_entry_value</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>,
* if the implementation supports <tt>null</tt> values.)
* @throws UnsupportedOperationException if the <tt>put</tt> operation
* is not supported by this map
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
* @throws NullPointerException if the specified key or value is null
* and this map does not permit null keys or values
* @throws IllegalArgumentException if some property of the specified key
* or value prevents it from being stored in this map
* @see #getNoEntryKey()
*/
V put( float key, V value);
/**
* Inserts a key/value pair into the map if the specified key is not already
* associated with a value.
*
* @param key key with which the specified value is to be associated
* @param value an <tt>float</tt> value to be associated with the specified key
*
* @return the previous value associated with <tt>key</tt>, or null
* if none was found.
*/
V putIfAbsent( float key, V value );
/**
* Removes the mapping for a key from this map if it is present
* (optional operation). More formally, if this map contains a mapping
* from key <tt>k</tt> to value <tt>v</tt> such that
* <code>key.equals(k)</code>, that mapping
* is removed. (The map can contain at most one such mapping.)
*
* <p>Returns the value to which this map previously associated the key,
* or <tt>null</tt> if the map contained no mapping for the key.
*
* <p>If this map permits null values, then a return value of
* <tt>null</tt> does not <i>necessarily</i> indicate that the map
* contained no mapping for the key; it's also possible that the map
* explicitly mapped the key to <tt>null</tt>.
*
* <p>The map will not contain a mapping for the specified key once the
* call returns.
*
* @param key key whose mapping is to be removed from the map
* @return the previous <tt>float</tt> value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* @throws UnsupportedOperationException if the <tt>remove</tt> operation
* is not supported by this map
* @throws ClassCastException if the key is of an inappropriate type for
* this map (optional)
* @throws NullPointerException if the specified key is null and this
* map does not permit null keys (optional)
*/
V remove( float key );
// Bulk Operations
/**
* Copies all of the mappings from the specified map to this map
* (optional operation). The effect of this call is equivalent to that
* of calling {@link #put(float,Object) put(k, v)} on this map once
* for each mapping from key <tt>k</tt> to value <tt>v</tt> in the
* specified map. The behavior of this operation is undefined if the
* specified map is modified while the operation is in progress.
*
* @param m mappings to be stored in this map
* @throws UnsupportedOperationException if the <tt>putAll</tt> operation
* is not supported by this map
* @throws ClassCastException if the class of a key or value in the
* specified map prevents it from being stored in this map
* @throws NullPointerException if the specified map is null, or if
* this map does not permit null keys or values, and the
* specified map contains null keys or values
* @throws IllegalArgumentException if some property of a key or value in
* the specified map prevents it from being stored in this map
*/
void putAll( Map<? extends Float, ? extends V> m);
/**
* Put all the entries from the given map into this map.
*
* @param map The map from which entries will be obtained to put into this map.
*/
void putAll( TFloatObjectMap<V> map );
/**
* Removes all of the mappings from this map (optional operation).
* The map will be empty after this call returns.
*
* @throws UnsupportedOperationException if the <tt>clear</tt> operation
* is not supported by this map
*/
void clear();
// Views
/**
* Returns a {@link TFloatSet} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is modified
* while an iteration over the set is in progress (except through
* the iterator's own <tt>remove</tt> operation), the results of
* the iteration are undefined. The set supports element removal,
* which removes the corresponding mapping from the map, via the
* <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
* operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
* operations.
*
* @return a set view of the keys contained in this map
*/
TFloatSet keySet();
/**
* Returns a copy of the keys of the map as an array.
* Changes to the array of keys will not be reflected in the map
* nor vice-versa.
*
* @return a copy of the keys of the map as an array.
*/
float[] keys();
/**
* Returns a copy of the keys of the map as an array.
* Changes to the array of keys will not be reflected in the map
* nor vice-versa.
*
* @param array the array into which the elements of the list are to be stored,
* if it is big enough; otherwise, a new array of the same type is
* allocated for this purpose.
* @return the keys of the map as an array.
*/
float[] keys( float[] array );
/**
* Returns a {@link Collection} view of the values contained in this map.
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. If the map is
* modified while an iteration over the collection is in progress
* (except through the iterator's own <tt>remove</tt> operation),
* the results of the iteration are undefined. The collection
* supports element removal, which removes the corresponding
* mapping from the map, via the <tt>Iterator.remove</tt>,
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
* <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
* support the <tt>add</tt> or <tt>addAll</tt> operations.
*
* @return a collection view of the values contained in this map
*/
Collection<V> valueCollection();
/**
* Returns the values of the map as an array of <tt>float</tt> values.
* Changes to the array of values will not be reflected in the map
* nor vice-versa.
*
* @return the values of the map as an array of <tt>float</tt> values.
*/
V[] values();
/**
* Returns the values of the map using an existing array.
* Changes to the array of values will not be reflected in the map
* nor vice-versa.
*
* @param array the array into which the elements of the list are to be stored,
* if it is big enough; otherwise, a new array of the same type is
* allocated for this purpose.
* @return the values of the map as an array of <tt>float</tt> values.
*/
<T> T[] values( T[] array );
/**
* Returns a <tt>TFloatObjectIterator</tt> with access to this map's keys and values.
*
* @return a <tt>TFloatObjectIterator</tt> with access to this map's keys and values.
*/
public TFloatObjectIterator<V> iterator();
/**
* Executes <tt>procedure</tt> for each key in the map.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the keys terminated because
* the procedure returned false for some key.
*/
public boolean forEachKey( TFloatProcedure procedure );
/**
* Executes <tt>procedure</tt> for each value in the map.
*
* @param procedure a <code>TObjectProcedure</code> value
* @return false if the loop over the values terminated because
* the procedure returned false for some value.
*/
public boolean forEachValue( TObjectProcedure<V> procedure );
/**
* Executes <tt>procedure</tt> for each key/value entry in the
* map.
*
* @param procedure a <code>TFloatObjectProcedure</code> value
* @return false if the loop over the entries terminated because
* the procedure returned false for some entry.
*/
public boolean forEachEntry( TFloatObjectProcedure<V> procedure );
/**
* Transform the values in this map using <tt>function</tt>.
*
* @param function a <code>TObjectFunction</code> value
*/
public void transformValues( TObjectFunction<V,V> function );
/**
* Retains only those entries in the map for which the procedure
* returns a true value.
*
* @param procedure determines which entries to keep
* @return true if the map was modified.
*/
public boolean retainEntries( TFloatObjectProcedure<V> procedure );
// Comparison and hashing
/**
* Compares the specified object with this map for equality. Returns
* <tt>true</tt> if the given object is also a map and the two maps
* represent the same mappings. More formally, two maps <tt>m1</tt> and
* <tt>m2</tt> represent the same mappings if
* <tt>m1.entrySet().equals(m2.entrySet())</tt>. This ensures that the
* <tt>equals</tt> method works properly across different implementations
* of the <tt>Map</tt> interface.
*
* @param o object to be compared for equality with this map
* @return <tt>true</tt> if the specified object is equal to this map
*/
boolean equals( Object o );
/**
* Returns the hash code value for this map. The hash code of a map is
* defined to be the sum of the hash codes of each entry in the map's
* <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>
* implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
* <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this map
* @see Object#equals(Object)
* @see #equals(Object)
*/
int hashCode();
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for procedures that take two parameters of type float and Object.
*/
public interface TFloatObjectProcedure<T> {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param a a <code>float</code> value
* @param b an <code>Object</code> value
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute( float a, T b );
}

View file

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for procedures with one float parameter.
*/
public interface TFloatProcedure {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param value a value of type <code>float</code>
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute( float value );
}

View file

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for procedures with one int parameter.
*/
public interface TIntProcedure {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param value a value of type <code>int</code>
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute( int value );
}

View file

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* Interface for procedures with one long parameter.
*/
public interface TLongProcedure {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param value a value of type <code>long</code>
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute( long value );
}

View file

@ -0,0 +1,42 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.procedure;
/**
* Interface for procedures with one Object parameter.
*
* Created: Mon Nov 5 21:45:49 2001
*
* @author Eric D. Friedman
* @version $Id: TObjectProcedure.java,v 1.1.2.1 2009/09/02 21:52:33 upholderoftruth Exp $
*/
public interface TObjectProcedure<T> {
/**
* Executes this procedure. A false return value indicates that
* the application executing this procedure should not invoke this
* procedure again.
*
* @param object an <code>Object</code> value
* @return true if additional invocations of the procedure are
* allowed.
*/
public boolean execute(T object);
}// TObjectProcedure

View file

@ -0,0 +1,320 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.set;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TFloatIterator;
import gnu.trove.procedure.TFloatProcedure;
import gnu.trove.TFloatCollection;
import java.util.Collection;
import java.util.Set;
import java.io.Serializable;
/**
* An implementation of the <tt>Set</tt> interface that uses an
* open-addressed hash table to store its contents.
*
* Created: Sat Nov 3 10:38:17 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $
*/
public interface TFloatSet extends TFloatCollection, Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
float getNoEntryValue();
/**
* Returns the number of elements in this set (its cardinality). If this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this set (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this set contains the specified element.
*
* @param entry an <code>float</code> value
* @return true if the set contains the specified element.
*/
boolean contains( float entry );
/**
* Creates an iterator over the values of the set. The iterator
* supports element deletion.
*
* @return an <code>TFloatIterator</code> value
*/
TFloatIterator iterator();
/**
* Returns an array containing all of the elements in this set.
* If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this set. (In other words, this method must
* allocate a new array even if this set is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this set
*/
float[] toArray();
/**
* Returns an array containing elements in this set.
*
* <p>If this set fits in the specified array with room to spare
* (i.e., the array has more elements than this set), the element in
* the array immediately following the end of the set is set to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this set <i>only</i> if the caller knows that this
* set does not contain any elements representing null.)
*
* <p>If the native array is smaller than the set size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this set are to be
* stored.
* @return an <tt>float[]</tt> containing all the elements in this set
* @throws NullPointerException if the specified array is null
*/
float[] toArray( float[] dest );
/**
* Inserts a value into the set.
*
* @param entry a <code>float</code> value
* @return true if the set was modified by the add operation
*/
boolean add( float entry );
/**
* Removes <tt>entry</tt> from the set.
*
* @param entry an <code>float</code> value
* @return true if the set was modified by the remove operation.
*/
boolean remove( float entry );
/**
* Tests the set to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the set to determine if all of the elements in
* <tt>TFloatCollection</tt> are present.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( TFloatCollection collection );
/**
* Tests the set to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of float primitives.
* @return true if all elements were present in the set.
*/
boolean containsAll( float[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( Collection<? extends Float> collection );
/**
* Adds all of the elements in the <tt>TFloatCollection</tt> to the set.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( TFloatCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the set.
*
* @param array a <code>array</code> of float primitives.
* @return true if the set was modified by the add all operation.
*/
boolean addAll( float[] array );
/**
* Removes any values in the set which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the set which are not contained in
* <tt>TFloatCollection</tt>.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( TFloatCollection collection );
/**
* Removes any values in the set which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of float primitives.
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( float[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TFloatCollection</tt> from the set.
*
* @param collection a <code>TFloatCollection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( TFloatCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the set.
*
* @param array an <code>array</code> of float primitives.
* @return true if the set was modified by the remove all operation.
*/
public boolean removeAll( float[] array );
/**
* Empties the set.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TFloatProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
boolean forEach( TFloatProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this set for equality. Returns
* <tt>true</tt> if the specified object is also a set, the two sets
* have the same size, and every member of the specified set is
* contained in this set (or equivalently, every member of this set is
* contained in the specified set). This definition ensures that the
* equals method works properly across different implementations of the
* set interface.
*
* @param o object to be compared for equality with this set
* @return <tt>true</tt> if the specified object is equal to this set
*/
boolean equals( Object o );
/**
* Returns the hash code value for this set. The hash code of a set is
* defined to be the sum of the hash codes of the elements in the set.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this set
* @see Object#equals(Object)
* @see Set#equals(Object)
*/
int hashCode();
} // THashSet

View file

@ -0,0 +1,320 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.set;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TIntIterator;
import gnu.trove.procedure.TIntProcedure;
import gnu.trove.TIntCollection;
import java.util.Collection;
import java.util.Set;
import java.io.Serializable;
/**
* An implementation of the <tt>Set</tt> interface that uses an
* open-addressed hash table to store its contents.
*
* Created: Sat Nov 3 10:38:17 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $
*/
public interface TIntSet extends TIntCollection, Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
int getNoEntryValue();
/**
* Returns the number of elements in this set (its cardinality). If this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this set (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this set contains the specified element.
*
* @param entry an <code>int</code> value
* @return true if the set contains the specified element.
*/
boolean contains( int entry );
/**
* Creates an iterator over the values of the set. The iterator
* supports element deletion.
*
* @return an <code>TIntIterator</code> value
*/
TIntIterator iterator();
/**
* Returns an array containing all of the elements in this set.
* If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this set. (In other words, this method must
* allocate a new array even if this set is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this set
*/
int[] toArray();
/**
* Returns an array containing elements in this set.
*
* <p>If this set fits in the specified array with room to spare
* (i.e., the array has more elements than this set), the element in
* the array immediately following the end of the set is set to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this set <i>only</i> if the caller knows that this
* set does not contain any elements representing null.)
*
* <p>If the native array is smaller than the set size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this set are to be
* stored.
* @return an <tt>int[]</tt> containing all the elements in this set
* @throws NullPointerException if the specified array is null
*/
int[] toArray( int[] dest );
/**
* Inserts a value into the set.
*
* @param entry a <code>int</code> value
* @return true if the set was modified by the add operation
*/
boolean add( int entry );
/**
* Removes <tt>entry</tt> from the set.
*
* @param entry an <code>int</code> value
* @return true if the set was modified by the remove operation.
*/
boolean remove( int entry );
/**
* Tests the set to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the set to determine if all of the elements in
* <tt>TIntCollection</tt> are present.
*
* @param collection a <code>TIntCollection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( TIntCollection collection );
/**
* Tests the set to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of int primitives.
* @return true if all elements were present in the set.
*/
boolean containsAll( int[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( Collection<? extends Integer> collection );
/**
* Adds all of the elements in the <tt>TIntCollection</tt> to the set.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( TIntCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the set.
*
* @param array a <code>array</code> of int primitives.
* @return true if the set was modified by the add all operation.
*/
boolean addAll( int[] array );
/**
* Removes any values in the set which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the set which are not contained in
* <tt>TIntCollection</tt>.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( TIntCollection collection );
/**
* Removes any values in the set which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of int primitives.
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( int[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TIntCollection</tt> from the set.
*
* @param collection a <code>TIntCollection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( TIntCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the set.
*
* @param array an <code>array</code> of int primitives.
* @return true if the set was modified by the remove all operation.
*/
public boolean removeAll( int[] array );
/**
* Empties the set.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TIntProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
boolean forEach( TIntProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this set for equality. Returns
* <tt>true</tt> if the specified object is also a set, the two sets
* have the same size, and every member of the specified set is
* contained in this set (or equivalently, every member of this set is
* contained in the specified set). This definition ensures that the
* equals method works properly across different implementations of the
* set interface.
*
* @param o object to be compared for equality with this set
* @return <tt>true</tt> if the specified object is equal to this set
*/
boolean equals( Object o );
/**
* Returns the hash code value for this set. The hash code of a set is
* defined to be the sum of the hash codes of the elements in the set.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this set
* @see Object#equals(Object)
* @see Set#equals(Object)
*/
int hashCode();
} // THashSet

View file

@ -0,0 +1,320 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.set;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
import gnu.trove.iterator.TLongIterator;
import gnu.trove.procedure.TLongProcedure;
import gnu.trove.TLongCollection;
import java.util.Collection;
import java.util.Set;
import java.io.Serializable;
/**
* An implementation of the <tt>Set</tt> interface that uses an
* open-addressed hash table to store its contents.
*
* Created: Sat Nov 3 10:38:17 2001
*
* @author Eric D. Friedman, Rob Eden, Jeff Randall
* @version $Id: _E_Set.template,v 1.1.2.5 2009/09/15 02:38:31 upholderoftruth Exp $
*/
public interface TLongSet extends TLongCollection, Serializable {
/**
* Returns the value that is used to represent null. The default
* value is generally zero, but can be changed during construction
* of the collection.
*
* @return the value that represents null
*/
long getNoEntryValue();
/**
* Returns the number of elements in this set (its cardinality). If this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
*
* @return the number of elements in this set (its cardinality)
*/
int size();
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
boolean isEmpty();
/**
* Returns <tt>true</tt> if this set contains the specified element.
*
* @param entry an <code>long</code> value
* @return true if the set contains the specified element.
*/
boolean contains( long entry );
/**
* Creates an iterator over the values of the set. The iterator
* supports element deletion.
*
* @return an <code>TLongIterator</code> value
*/
TLongIterator iterator();
/**
* Returns an array containing all of the elements in this set.
* If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the
* elements in the same order.
*
* <p>The returned array will be "safe" in that no references to it
* are maintained by this set. (In other words, this method must
* allocate a new array even if this set is backed by an array).
* The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all the elements in this set
*/
long[] toArray();
/**
* Returns an array containing elements in this set.
*
* <p>If this set fits in the specified array with room to spare
* (i.e., the array has more elements than this set), the element in
* the array immediately following the end of the set is set to
* <tt>{@link #getNoEntryValue()}</tt>. (This is useful in determining
* the length of this set <i>only</i> if the caller knows that this
* set does not contain any elements representing null.)
*
* <p>If the native array is smaller than the set size,
* the array will be filled with elements in Iterator order
* until it is full and exclude the remainder.
*
* <p>If this set makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements
* in the same order.
*
* @param dest the array into which the elements of this set are to be
* stored.
* @return an <tt>long[]</tt> containing all the elements in this set
* @throws NullPointerException if the specified array is null
*/
long[] toArray( long[] dest );
/**
* Inserts a value into the set.
*
* @param entry a <code>long</code> value
* @return true if the set was modified by the add operation
*/
boolean add( long entry );
/**
* Removes <tt>entry</tt> from the set.
*
* @param entry an <code>long</code> value
* @return true if the set was modified by the remove operation.
*/
boolean remove( long entry );
/**
* Tests the set to determine if all of the elements in
* <tt>collection</tt> are present.
*
* @param collection a <code>Collection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( Collection<?> collection );
/**
* Tests the set to determine if all of the elements in
* <tt>TLongCollection</tt> are present.
*
* @param collection a <code>TLongCollection</code> value
* @return true if all elements were present in the set.
*/
boolean containsAll( TLongCollection collection );
/**
* Tests the set to determine if all of the elements in
* <tt>array</tt> are present.
*
* @param array as <code>array</code> of long primitives.
* @return true if all elements were present in the set.
*/
boolean containsAll( long[] array );
/**
* Adds all of the elements in <tt>collection</tt> to the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( Collection<? extends Long> collection );
/**
* Adds all of the elements in the <tt>TLongCollection</tt> to the set.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the set was modified by the add all operation.
*/
boolean addAll( TLongCollection collection );
/**
* Adds all of the elements in the <tt>array</tt> to the set.
*
* @param array a <code>array</code> of long primitives.
* @return true if the set was modified by the add all operation.
*/
boolean addAll( long[] array );
/**
* Removes any values in the set which are not contained in
* <tt>collection</tt>.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( Collection<?> collection );
/**
* Removes any values in the set which are not contained in
* <tt>TLongCollection</tt>.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( TLongCollection collection );
/**
* Removes any values in the set which are not contained in
* <tt>array</tt>.
*
* @param array an <code>array</code> of long primitives.
* @return true if the set was modified by the retain all operation
*/
boolean retainAll( long[] array );
/**
* Removes all of the elements in <tt>collection</tt> from the set.
*
* @param collection a <code>Collection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( Collection<?> collection );
/**
* Removes all of the elements in <tt>TLongCollection</tt> from the set.
*
* @param collection a <code>TLongCollection</code> value
* @return true if the set was modified by the remove all operation.
*/
boolean removeAll( TLongCollection collection );
/**
* Removes all of the elements in <tt>array</tt> from the set.
*
* @param array an <code>array</code> of long primitives.
* @return true if the set was modified by the remove all operation.
*/
public boolean removeAll( long[] array );
/**
* Empties the set.
*/
void clear();
/**
* Executes <tt>procedure</tt> for each element in the set.
*
* @param procedure a <code>TLongProcedure</code> value
* @return false if the loop over the set terminated because
* the procedure returned false for some value.
*/
boolean forEach( TLongProcedure procedure );
// Comparison and hashing
/**
* Compares the specified object with this set for equality. Returns
* <tt>true</tt> if the specified object is also a set, the two sets
* have the same size, and every member of the specified set is
* contained in this set (or equivalently, every member of this set is
* contained in the specified set). This definition ensures that the
* equals method works properly across different implementations of the
* set interface.
*
* @param o object to be compared for equality with this set
* @return <tt>true</tt> if the specified object is equal to this set
*/
boolean equals( Object o );
/**
* Returns the hash code value for this set. The hash code of a set is
* defined to be the sum of the hash codes of the elements in the set.
* This ensures that <tt>s1.equals(s2)</tt> implies that
* <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
* and <tt>s2</tt>, as required by the general contract of
* {@link Object#hashCode}.
*
* @return the hash code value for this set
* @see Object#equals(Object)
* @see Set#equals(Object)
*/
int hashCode();
} // THashSet

View file

@ -0,0 +1,551 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.set.hash;
import gnu.trove.set.TIntSet;
import gnu.trove.iterator.TIntIterator;
import gnu.trove.impl.*;
import gnu.trove.impl.hash.*;
import gnu.trove.TIntCollection;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Externalizable;
import java.util.Arrays;
import java.util.Collection;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed set implementation for int primitives.
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
*/
public class TIntHashSet extends TIntHash implements TIntSet, Externalizable {
static final long serialVersionUID = 1L;
/**
* Creates a new <code>TIntHashSet</code> instance with the default
* capacity and load factor.
*/
public TIntHashSet() {
super();
}
/**
* Creates a new <code>TIntHashSet</code> instance with a prime
* capacity equal to or greater than <tt>initialCapacity</tt> and
* with the default load factor.
*
* @param initialCapacity an <code>int</code> value
*/
public TIntHashSet( int initialCapacity ) {
super( initialCapacity );
}
/**
* Creates a new <code>TIntHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param load_factor used to calculate the threshold over which
* rehashing takes place.
*/
public TIntHashSet( int initialCapacity, float load_factor ) {
super( initialCapacity, load_factor );
}
/**
* Creates a new <code>TIntHashSet</code> instance with a prime
* capacity equal to or greater than <tt>initial_capacity</tt> and
* with the specified load factor.
*
* @param initial_capacity an <code>int</code> value
* @param load_factor a <code>float</code> value
* @param no_entry_value a <code>int</code> value that represents null.
*/
public TIntHashSet( int initial_capacity, float load_factor,
int no_entry_value ) {
super( initial_capacity, load_factor, no_entry_value );
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TIntHashSet</code> instance that is a copy
* of the existing Collection.
*
* @param collection a <tt>Collection</tt> that will be duplicated.
*/
public TIntHashSet( Collection<? extends Integer> collection ) {
this( Math.max( collection.size(), DEFAULT_CAPACITY ) );
addAll( collection );
}
/**
* Creates a new <code>TIntHashSet</code> instance that is a copy
* of the existing set.
*
* @param collection a <tt>TIntSet</tt> that will be duplicated.
*/
public TIntHashSet( TIntCollection collection ) {
this( Math.max( collection.size(), DEFAULT_CAPACITY ) );
if ( collection instanceof TIntHashSet ) {
TIntHashSet hashset = ( TIntHashSet ) collection;
this._loadFactor = hashset._loadFactor;
this.no_entry_value = hashset.no_entry_value;
//noinspection RedundantCast
if ( this.no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, this.no_entry_value );
}
setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) );
}
addAll( collection );
}
/**
* Creates a new <code>TIntHashSet</code> instance containing the
* elements of <tt>array</tt>.
*
* @param array an array of <code>int</code> primitives
*/
public TIntHashSet( int[] array ) {
this( Math.max( array.length, DEFAULT_CAPACITY ) );
addAll( array );
}
/** {@inheritDoc} */
public TIntIterator iterator() {
return new TIntHashIterator( this );
}
/** {@inheritDoc} */
public int[] toArray() {
int[] result = new int[ size() ];
int[] set = _set;
byte[] states = _states;
for ( int i = states.length, j = 0; i-- > 0; ) {
if ( states[i] == FULL ) {
result[j++] = set[i];
}
}
return result;
}
/** {@inheritDoc} */
public int[] toArray( int[] dest ) {
int[] set = _set;
byte[] states = _states;
for ( int i = states.length, j = 0; i-- > 0; ) {
if ( states[i] == FULL ) {
dest[j++] = set[i];
}
}
if ( dest.length > _size ) {
dest[_size] = no_entry_value;
}
return dest;
}
/** {@inheritDoc} */
public boolean add( int val ) {
int index = insertionIndex(val);
if ( index < 0 ) {
return false; // already present in set, nothing to add
}
byte previousState = _states[index];
_set[index] = val;
_states[index] = FULL;
postInsertHook( previousState == FREE );
return true; // yes, we added something
}
/** {@inheritDoc} */
public boolean remove( int val ) {
int index = index(val);
if ( index >= 0 ) {
removeAt( index );
return true;
}
return false;
}
/** {@inheritDoc} */
public boolean containsAll( Collection<?> collection ) {
for ( Object element : collection ) {
if ( element instanceof Integer ) {
int c = ( ( Integer ) element ).intValue();
if ( ! contains( c ) ) {
return false;
}
} else {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean containsAll( TIntCollection collection ) {
TIntIterator iter = collection.iterator();
while ( iter.hasNext() ) {
int element = iter.next();
if ( ! contains( element ) ) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean containsAll( int[] array ) {
for ( int i = array.length; i-- > 0; ) {
if ( ! contains( array[i] ) ) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean addAll( Collection<? extends Integer> collection ) {
boolean changed = false;
for ( Integer element : collection ) {
int e = element.intValue();
if ( add( e ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean addAll( TIntCollection collection ) {
boolean changed = false;
TIntIterator iter = collection.iterator();
while ( iter.hasNext() ) {
int element = iter.next();
if ( add( element ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean addAll( int[] array ) {
boolean changed = false;
for ( int i = array.length; i-- > 0; ) {
if ( add( array[i] ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
@SuppressWarnings({"SuspiciousMethodCalls"})
public boolean retainAll( Collection<?> collection ) {
boolean modified = false;
TIntIterator iter = iterator();
while ( iter.hasNext() ) {
if ( ! collection.contains( Integer.valueOf ( iter.next() ) ) ) {
iter.remove();
modified = true;
}
}
return modified;
}
/** {@inheritDoc} */
public boolean retainAll( TIntCollection collection ) {
if ( this == collection ) {
return false;
}
boolean modified = false;
TIntIterator iter = iterator();
while ( iter.hasNext() ) {
if ( ! collection.contains( iter.next() ) ) {
iter.remove();
modified = true;
}
}
return modified;
}
/** {@inheritDoc} */
public boolean retainAll( int[] array ) {
boolean changed = false;
Arrays.sort( array );
int[] set = _set;
byte[] states = _states;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) {
removeAt( i );
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( Collection<?> collection ) {
boolean changed = false;
for ( Object element : collection ) {
if ( element instanceof Integer ) {
int c = ( ( Integer ) element ).intValue();
if ( remove( c ) ) {
changed = true;
}
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( TIntCollection collection ) {
boolean changed = false;
TIntIterator iter = collection.iterator();
while ( iter.hasNext() ) {
int element = iter.next();
if ( remove( element ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( int[] array ) {
boolean changed = false;
for ( int i = array.length; i-- > 0; ) {
if ( remove(array[i]) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public void clear() {
super.clear();
int[] set = _set;
byte[] states = _states;
for ( int i = set.length; i-- > 0; ) {
set[i] = no_entry_value;
states[i] = FREE;
}
}
/** {@inheritDoc} */
protected void rehash( int newCapacity ) {
int oldCapacity = _set.length;
int oldSet[] = _set;
byte oldStates[] = _states;
_set = new int[newCapacity];
_states = new byte[newCapacity];
for ( int i = oldCapacity; i-- > 0; ) {
if( oldStates[i] == FULL ) {
int o = oldSet[i];
int index = insertionIndex(o);
_set[index] = o;
_states[index] = FULL;
}
}
}
/** {@inheritDoc} */
public boolean equals( Object other ) {
if ( ! ( other instanceof TIntSet ) ) {
return false;
}
TIntSet that = ( TIntSet ) other;
if ( that.size() != this.size() ) {
return false;
}
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
if ( ! that.contains( _set[i] ) ) {
return false;
}
}
}
return true;
}
/** {@inheritDoc} */
public int hashCode() {
int hashcode = 0;
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
hashcode += HashFunctions.hash( _set[i] );
}
}
return hashcode;
}
/** {@inheritDoc} */
public String toString() {
StringBuilder buffy = new StringBuilder( _size * 2 + 2 );
buffy.append("{");
for ( int i = _states.length, j = 1; i-- > 0; ) {
if ( _states[i] == FULL ) {
buffy.append( _set[i] );
if ( j++ < _size ) {
buffy.append( "," );
}
}
}
buffy.append("}");
return buffy.toString();
}
class TIntHashIterator extends THashPrimitiveIterator implements TIntIterator {
/** the collection on which the iterator operates */
private final TIntHash _hash;
/** {@inheritDoc} */
public TIntHashIterator( TIntHash hash ) {
super( hash );
this._hash = hash;
}
/** {@inheritDoc} */
public int next() {
moveToNextIndex();
return _hash._set[_index];
}
}
/** {@inheritDoc} */
public void writeExternal( ObjectOutput out ) throws IOException {
// VERSION
out.writeByte( 1 );
// SUPER
super.writeExternal( out );
// NUMBER OF ENTRIES
out.writeInt( _size );
// LOAD FACTOR -- Added version 1
out.writeFloat( _loadFactor );
// NO ENTRY VALUE -- Added version 1
out.writeInt( no_entry_value );
// ENTRIES
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
out.writeInt( _set[i] );
}
}
}
/** {@inheritDoc} */
public void readExternal( ObjectInput in )
throws IOException, ClassNotFoundException {
// VERSION
int version = in.readByte();
// SUPER
super.readExternal( in );
// NUMBER OF ENTRIES
int size = in.readInt();
if ( version >= 1 ) {
// LOAD FACTOR
_loadFactor = in.readFloat();
// NO ENTRY VALUE
no_entry_value = in.readInt();
//noinspection RedundantCast
if ( no_entry_value != ( int ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
// ENTRIES
setUp( size );
while ( size-- > 0 ) {
int val = in.readInt();
add( val );
}
}
} // TIntHashSet

View file

@ -0,0 +1,551 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
// Copyright (c) 2009, Rob Eden All Rights Reserved.
// Copyright (c) 2009, Jeff Randall All Rights Reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
package gnu.trove.set.hash;
import gnu.trove.set.TLongSet;
import gnu.trove.iterator.TLongIterator;
import gnu.trove.impl.*;
import gnu.trove.impl.hash.*;
import gnu.trove.TLongCollection;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Externalizable;
import java.util.Arrays;
import java.util.Collection;
//////////////////////////////////////////////////
// THIS IS A GENERATED CLASS. DO NOT HAND EDIT! //
//////////////////////////////////////////////////
/**
* An open addressed set implementation for long primitives.
*
* @author Eric D. Friedman
* @author Rob Eden
* @author Jeff Randall
*/
public class TLongHashSet extends TLongHash implements TLongSet, Externalizable {
static final long serialVersionUID = 1L;
/**
* Creates a new <code>TLongHashSet</code> instance with the default
* capacity and load factor.
*/
public TLongHashSet() {
super();
}
/**
* Creates a new <code>TLongHashSet</code> instance with a prime
* capacity equal to or greater than <tt>initialCapacity</tt> and
* with the default load factor.
*
* @param initialCapacity an <code>int</code> value
*/
public TLongHashSet( int initialCapacity ) {
super( initialCapacity );
}
/**
* Creates a new <code>TIntHash</code> instance with a prime
* value at or near the specified capacity and load factor.
*
* @param initialCapacity used to find a prime capacity for the table.
* @param load_factor used to calculate the threshold over which
* rehashing takes place.
*/
public TLongHashSet( int initialCapacity, float load_factor ) {
super( initialCapacity, load_factor );
}
/**
* Creates a new <code>TLongHashSet</code> instance with a prime
* capacity equal to or greater than <tt>initial_capacity</tt> and
* with the specified load factor.
*
* @param initial_capacity an <code>int</code> value
* @param load_factor a <code>float</code> value
* @param no_entry_value a <code>long</code> value that represents null.
*/
public TLongHashSet( int initial_capacity, float load_factor,
long no_entry_value ) {
super( initial_capacity, load_factor, no_entry_value );
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
/**
* Creates a new <code>TLongHashSet</code> instance that is a copy
* of the existing Collection.
*
* @param collection a <tt>Collection</tt> that will be duplicated.
*/
public TLongHashSet( Collection<? extends Long> collection ) {
this( Math.max( collection.size(), DEFAULT_CAPACITY ) );
addAll( collection );
}
/**
* Creates a new <code>TLongHashSet</code> instance that is a copy
* of the existing set.
*
* @param collection a <tt>TLongSet</tt> that will be duplicated.
*/
public TLongHashSet( TLongCollection collection ) {
this( Math.max( collection.size(), DEFAULT_CAPACITY ) );
if ( collection instanceof TLongHashSet ) {
TLongHashSet hashset = ( TLongHashSet ) collection;
this._loadFactor = hashset._loadFactor;
this.no_entry_value = hashset.no_entry_value;
//noinspection RedundantCast
if ( this.no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, this.no_entry_value );
}
setUp( (int) Math.ceil( DEFAULT_CAPACITY / _loadFactor ) );
}
addAll( collection );
}
/**
* Creates a new <code>TLongHashSet</code> instance containing the
* elements of <tt>array</tt>.
*
* @param array an array of <code>long</code> primitives
*/
public TLongHashSet( long[] array ) {
this( Math.max( array.length, DEFAULT_CAPACITY ) );
addAll( array );
}
/** {@inheritDoc} */
public TLongIterator iterator() {
return new TLongHashIterator( this );
}
/** {@inheritDoc} */
public long[] toArray() {
long[] result = new long[ size() ];
long[] set = _set;
byte[] states = _states;
for ( int i = states.length, j = 0; i-- > 0; ) {
if ( states[i] == FULL ) {
result[j++] = set[i];
}
}
return result;
}
/** {@inheritDoc} */
public long[] toArray( long[] dest ) {
long[] set = _set;
byte[] states = _states;
for ( int i = states.length, j = 0; i-- > 0; ) {
if ( states[i] == FULL ) {
dest[j++] = set[i];
}
}
if ( dest.length > _size ) {
dest[_size] = no_entry_value;
}
return dest;
}
/** {@inheritDoc} */
public boolean add( long val ) {
int index = insertionIndex(val);
if ( index < 0 ) {
return false; // already present in set, nothing to add
}
byte previousState = _states[index];
_set[index] = val;
_states[index] = FULL;
postInsertHook( previousState == FREE );
return true; // yes, we added something
}
/** {@inheritDoc} */
public boolean remove( long val ) {
int index = index(val);
if ( index >= 0 ) {
removeAt( index );
return true;
}
return false;
}
/** {@inheritDoc} */
public boolean containsAll( Collection<?> collection ) {
for ( Object element : collection ) {
if ( element instanceof Long ) {
long c = ( ( Long ) element ).longValue();
if ( ! contains( c ) ) {
return false;
}
} else {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean containsAll( TLongCollection collection ) {
TLongIterator iter = collection.iterator();
while ( iter.hasNext() ) {
long element = iter.next();
if ( ! contains( element ) ) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean containsAll( long[] array ) {
for ( int i = array.length; i-- > 0; ) {
if ( ! contains( array[i] ) ) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
public boolean addAll( Collection<? extends Long> collection ) {
boolean changed = false;
for ( Long element : collection ) {
long e = element.longValue();
if ( add( e ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean addAll( TLongCollection collection ) {
boolean changed = false;
TLongIterator iter = collection.iterator();
while ( iter.hasNext() ) {
long element = iter.next();
if ( add( element ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean addAll( long[] array ) {
boolean changed = false;
for ( int i = array.length; i-- > 0; ) {
if ( add( array[i] ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
@SuppressWarnings({"SuspiciousMethodCalls"})
public boolean retainAll( Collection<?> collection ) {
boolean modified = false;
TLongIterator iter = iterator();
while ( iter.hasNext() ) {
if ( ! collection.contains( Long.valueOf ( iter.next() ) ) ) {
iter.remove();
modified = true;
}
}
return modified;
}
/** {@inheritDoc} */
public boolean retainAll( TLongCollection collection ) {
if ( this == collection ) {
return false;
}
boolean modified = false;
TLongIterator iter = iterator();
while ( iter.hasNext() ) {
if ( ! collection.contains( iter.next() ) ) {
iter.remove();
modified = true;
}
}
return modified;
}
/** {@inheritDoc} */
public boolean retainAll( long[] array ) {
boolean changed = false;
Arrays.sort( array );
long[] set = _set;
byte[] states = _states;
for ( int i = set.length; i-- > 0; ) {
if ( states[i] == FULL && ( Arrays.binarySearch( array, set[i] ) < 0) ) {
removeAt( i );
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( Collection<?> collection ) {
boolean changed = false;
for ( Object element : collection ) {
if ( element instanceof Long ) {
long c = ( ( Long ) element ).longValue();
if ( remove( c ) ) {
changed = true;
}
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( TLongCollection collection ) {
boolean changed = false;
TLongIterator iter = collection.iterator();
while ( iter.hasNext() ) {
long element = iter.next();
if ( remove( element ) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public boolean removeAll( long[] array ) {
boolean changed = false;
for ( int i = array.length; i-- > 0; ) {
if ( remove(array[i]) ) {
changed = true;
}
}
return changed;
}
/** {@inheritDoc} */
public void clear() {
super.clear();
long[] set = _set;
byte[] states = _states;
for ( int i = set.length; i-- > 0; ) {
set[i] = no_entry_value;
states[i] = FREE;
}
}
/** {@inheritDoc} */
protected void rehash( int newCapacity ) {
int oldCapacity = _set.length;
long oldSet[] = _set;
byte oldStates[] = _states;
_set = new long[newCapacity];
_states = new byte[newCapacity];
for ( int i = oldCapacity; i-- > 0; ) {
if( oldStates[i] == FULL ) {
long o = oldSet[i];
int index = insertionIndex(o);
_set[index] = o;
_states[index] = FULL;
}
}
}
/** {@inheritDoc} */
public boolean equals( Object other ) {
if ( ! ( other instanceof TLongSet ) ) {
return false;
}
TLongSet that = ( TLongSet ) other;
if ( that.size() != this.size() ) {
return false;
}
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
if ( ! that.contains( _set[i] ) ) {
return false;
}
}
}
return true;
}
/** {@inheritDoc} */
public int hashCode() {
int hashcode = 0;
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
hashcode += HashFunctions.hash( _set[i] );
}
}
return hashcode;
}
/** {@inheritDoc} */
public String toString() {
StringBuilder buffy = new StringBuilder( _size * 2 + 2 );
buffy.append("{");
for ( int i = _states.length, j = 1; i-- > 0; ) {
if ( _states[i] == FULL ) {
buffy.append( _set[i] );
if ( j++ < _size ) {
buffy.append( "," );
}
}
}
buffy.append("}");
return buffy.toString();
}
class TLongHashIterator extends THashPrimitiveIterator implements TLongIterator {
/** the collection on which the iterator operates */
private final TLongHash _hash;
/** {@inheritDoc} */
public TLongHashIterator( TLongHash hash ) {
super( hash );
this._hash = hash;
}
/** {@inheritDoc} */
public long next() {
moveToNextIndex();
return _hash._set[_index];
}
}
/** {@inheritDoc} */
public void writeExternal( ObjectOutput out ) throws IOException {
// VERSION
out.writeByte( 1 );
// SUPER
super.writeExternal( out );
// NUMBER OF ENTRIES
out.writeInt( _size );
// LOAD FACTOR -- Added version 1
out.writeFloat( _loadFactor );
// NO ENTRY VALUE -- Added version 1
out.writeLong( no_entry_value );
// ENTRIES
for ( int i = _states.length; i-- > 0; ) {
if ( _states[i] == FULL ) {
out.writeLong( _set[i] );
}
}
}
/** {@inheritDoc} */
public void readExternal( ObjectInput in )
throws IOException, ClassNotFoundException {
// VERSION
int version = in.readByte();
// SUPER
super.readExternal( in );
// NUMBER OF ENTRIES
int size = in.readInt();
if ( version >= 1 ) {
// LOAD FACTOR
_loadFactor = in.readFloat();
// NO ENTRY VALUE
no_entry_value = in.readLong();
//noinspection RedundantCast
if ( no_entry_value != ( long ) 0 ) {
Arrays.fill( _set, no_entry_value );
}
}
// ENTRIES
setUp( size );
while ( size-- > 0 ) {
long val = in.readLong();
add( val );
}
}
} // TIntHashSet

View file

@ -1,134 +1,107 @@
package net.osmand.osm;
package net.osmand.binary;
import net.osmand.Algoritms;
import net.osmand.osm.MapRenderingTypes;
public class BinaryMapRenderObject {
private String name = null;
private int type;
private byte[] data = null;
private long id;
private float order = -1;
private boolean multitype = false;
private boolean highwayType = false;
public class BinaryMapDataObject {
int[] coordinates = null;
int[] types = null;
public BinaryMapRenderObject(long id){
this.id = id;
int stringId = -1;
long id = 0;
long[] restrictions = null;
int highwayAttributes = 0;
String name;
public BinaryMapDataObject(){
}
public void setData(byte[] data) {
this.data = data;
protected void setStringId(int stringId) {
this.stringId = stringId;
}
protected void setCoordinates(int[] coordinates) {
this.coordinates = coordinates;
}
protected int getStringId() {
return stringId;
}
public void setName(String name) {
this.name = name;
}
public void setType(int type) {
this.type = type;
multitype = (type & 1) > 0;
highwayType = isHighwayType();
order = -1;
}
public int getWholeType() {
return type;
}
public long getId() {
return id;
}
public boolean isMultitype() {
return multitype;
}
public byte getMultiTypes(){
return multitype ? data[0] : 0;
}
public byte getRestrictions(){
if(!highwayType){
return 0;
}
if(multitype){
return data[1];
}
return data[0];
}
public int getAdditionalType(int k){
return Algoritms.parseSmallIntFromBytes(data, highwayType ? k * 2 + 2 : k * 2 + 1);
}
// do not cut type to 15 bits (16 bits needed for multipolygon)
public int getMainType(){
return (type >> 1);
}
private boolean isHighwayType(){
int pr = type >> 1;
return (pr & 3) == MapRenderingTypes.POLYLINE_TYPE && MapRenderingTypes.getMainObjectType(pr) == MapRenderingTypes.HIGHWAY;
}
public int getSecondType(){
if(isHighwayType()){
return 0;
}
return type >> 16;
}
public byte getRestrictionType(int k){
int offset = multitype ? data[0] * 2 + 2 : 1;
long l = Algoritms.parseLongFromBytes(data, offset);
return (byte) (l & 7);
}
public long getRestriction(int k){
int offset = multitype ? data[0] * 2 + 2 : 1;
long l = Algoritms.parseLongFromBytes(data, offset);
return (l & ~7l) | (id & 7l);
}
public int getPointsLength() {
if (data == null || data.length == 0) {
return 0;
}
return (data.length - getShiftCoordinates()) / 8;
}
public String getName() {
return name;
}
private int getShiftCoordinates(){
int shift = 0;
if(multitype){
shift = data[0] * 2 + 1;
if(highwayType){
shift += data[1] * 8 + 1;
}
} else if(highwayType){
shift = data[0] * 8 + 1;
}
return shift;
public int[] getTypes(){
return types;
}
public long getId() {
return id;
}
protected void setId(long id) {
this.id = id;
}
protected void setTypes(int[] types) {
this.types = types;
}
public int getHighwayAttributes() {
return highwayAttributes;
}
protected void setHighwayAttributes(int highwayAttributes) {
this.highwayAttributes = highwayAttributes;
}
public int getPointsLength(){
if(coordinates == null){
return 0;
}
return coordinates.length / 2;
}
public int getPoint31YTile(int ind) {
return Algoritms.parseIntFromBytes(data, ind * 8 + getShiftCoordinates());
return coordinates[2 * ind + 1];
}
public int getPoint31XTile(int ind) {
return Algoritms.parseIntFromBytes(data, ind * 8 + 4 + getShiftCoordinates());
return coordinates[2 * ind];
}
public float getMapOrder(){
if (order == -1) {
order = getOrder(getMainType());
public int getRestrictionCount(){
if(restrictions == null){
return 0;
}
return order;
return restrictions.length;
}
protected void setRestrictions(long[] restrictions) {
this.restrictions = restrictions;
}
protected long[] getRestrictions() {
return restrictions;
}
public byte getRestrictionType(int k){
return (byte) (restrictions[k] & 7);
}
public long getRestriction(int k){
long l = restrictions[k];
return (l & ~7l) | (id & 7l);
}
public static float getOrder(int wholeType) {
float order = 0;
@ -233,6 +206,6 @@ public class BinaryMapRenderObject {
return order;
}
}

View file

@ -45,22 +45,6 @@ public class BinaryMapIndexReader {
}
public class MapDataObject {
int[] coordinates = null;
int[] types = null;
int stringId = -1;
long id = 0;
long[] restrictions = null;
int highwayAttributes = 0;
String name;
}
public BinaryMapIndexReader(final RandomAccessFile raf) throws IOException {
this.raf = raf;
@ -183,8 +167,8 @@ public class BinaryMapIndexReader {
}
}
public List<MapDataObject> searchMapIndex(MapRoot index, int sleft, int sright, int stop, int sbottom,
List<MapDataObject> searchResults) throws IOException {
public List<BinaryMapDataObject> searchMapIndex(MapRoot index, int sleft, int sright, int stop, int sbottom,
List<BinaryMapDataObject> searchResults) throws IOException {
for(MapTree tree : index.trees){
codedIS.seek(tree.filePointer);
int oldLimit = codedIS.pushLimit(tree.length);
@ -197,9 +181,9 @@ public class BinaryMapIndexReader {
private void searchMapTreeBounds(MapTree tree, int pleft, int pright, int ptop, int pbottom,
int sleft, int sright, int stop, int sbottom,
List<MapDataObject> searchResults, String indent) throws IOException {
List<BinaryMapDataObject> searchResults, String indent) throws IOException {
int init = 0;
List<MapDataObject> results = null;
List<BinaryMapDataObject> results = null;
while(true){
int tag = WireFormat.getTagFieldNumber(codedIS.readTag());
if(init == 0xf){
@ -231,10 +215,10 @@ public class BinaryMapIndexReader {
case OsmandOdb.MapTree.LEAFS_FIELD_NUMBER :
int length = codedIS.readRawVarint32();
int oldLimit = codedIS.pushLimit(length);
MapDataObject mapObject = readMapDataObject(tree.left, tree.right, tree.top, tree.bottom, sleft, sright, stop, sbottom);
BinaryMapDataObject mapObject = readMapDataObject(tree.left, tree.right, tree.top, tree.bottom, sleft, sright, stop, sbottom);
if(mapObject != null){
if(results == null){
results = new ArrayList<MapDataObject>();
results = new ArrayList<BinaryMapDataObject>();
}
results.add(mapObject);
searchResults.add(mapObject);
@ -255,7 +239,7 @@ public class BinaryMapIndexReader {
case OsmandOdb.MapTree.BASEID_FIELD_NUMBER :
tree.baseId = codedIS.readUInt64();
if (results != null) {
for (MapDataObject rs : results) {
for (BinaryMapDataObject rs : results) {
rs.id += tree.baseId;
if (rs.restrictions != null) {
for (int i = 0; i < rs.restrictions.length; i++) {
@ -272,7 +256,7 @@ public class BinaryMapIndexReader {
codedIS.popLimit(oldLimit);
if (results != null) {
for (MapDataObject rs : results) {
for (BinaryMapDataObject rs : results) {
if (rs.stringId != -1) {
rs.name = tree.stringTable.get(rs.stringId);
}
@ -286,7 +270,7 @@ public class BinaryMapIndexReader {
}
}
List<Integer> CACHE = new ArrayList<Integer>();
private MapDataObject readMapDataObject(int left, int right, int top, int bottom, int sleft, int sright, int stop, int sbottom) throws IOException {
private BinaryMapDataObject readMapDataObject(int left, int right, int top, int bottom, int sleft, int sright, int stop, int sbottom) throws IOException {
int tag = WireFormat.getTagFieldNumber(codedIS.readTag());
if(OsmandOdb.MapData.COORDINATES_FIELD_NUMBER != tag) {
throw new IllegalArgumentException();
@ -314,7 +298,7 @@ public class BinaryMapIndexReader {
return null;
}
MapDataObject dataObject = new MapDataObject();
BinaryMapDataObject dataObject = new BinaryMapDataObject();
dataObject.coordinates = new int[CACHE.size()];
for(int i=0; i<CACHE.size(); i++){
dataObject.coordinates[i] = CACHE.get(i);
@ -410,9 +394,9 @@ public class BinaryMapIndexReader {
for(MapRoot b : reader.getMapIndexes()) {
System.out.println(b.minZoom + " " + b.maxZoom + " " +b.trees.size() + " "
+ b.left + " " + b.right + " " + b.top + " " + b.bottom);
for(MapDataObject obj : reader.searchMapIndex(b, sleft, sright, stop, sbottom, new ArrayList<MapDataObject>())){
if(obj.name != null){
System.out.println(" " + obj.name);
for(BinaryMapDataObject obj : reader.searchMapIndex(b, sleft, sright, stop, sbottom, new ArrayList<BinaryMapDataObject>())){
if(obj.getName() != null){
System.out.println(" " + obj.getName());
}
}
}

View file

@ -0,0 +1,67 @@
option java_package = "net.osmand.binary";
//protoc --java_out=../.. osmand_odb.proto
//
// STORAGE LAYER: Storing primitives.
//
// IMPORTANT : These messages are not intented to be parsed by google engine (because of the size)
// The main difference that size of that messages is not var int and is always fixed int size
message OsmAndStructure {
required uint32 version = 1;
repeated OsmAndMapIndex mapIndex = 2;
}
message OsmAndMapIndex {
repeated MapRootLevel levels = 1;
}
message MapRootLevel {
required int32 maxZoom = 1;
required int32 minZoom = 2;
required int32 left = 3;
required int32 right = 4;
required int32 top = 5;
required int32 bottom = 6;
repeated MapTree root = 7;
}
message MapTree {
required sint32 left = 1; // delta encoded
required sint32 right = 2; // delta encoded
required sint32 top = 3; // delta encoded
required sint32 bottom = 4; // delta encoded
optional StringTable stringTable = 5;
optional uint64 baseId = 6;
repeated MapTree subtrees = 7;
repeated MapData leafs = 8;
}
// These messages could be read directly
/**
String table, contains the common strings in each block.
*/
message StringTable {
repeated string s = 1;
}
/// Simple messages
message MapData {
required bytes coordinates = 1; // array of delta x,y sint32 could be read by codedinputstream
// first x delta to Tree.left, y to delta Tree.top (next delta to previous)
required bytes types = 2; // array of fixed int16
required sint64 id = 3; // delta encoded
optional uint32 stringId = 4;
optional bytes restrictions = 5; // array of SInt64 delta encoded (to baseId !)
optional int32 highwayMeta = 6;
}

View file

@ -0,0 +1,207 @@
option java_package = "crosby.binary";
/* OSM Binary file format
This is the master schema file of the OSM binary file format. This
file is designed to support limited random-access and future
extendability.
A binary OSM file consists of a sequence of FileBlocks (please see
fileformat.proto). The first fileblock contains a serialized instance
of HeaderBlock, followed by a sequence of PrimitiveBlock blocks that
contain the primitives.
Each primitiveblock is designed to be independently parsable. It
contains a string table storing all strings in that block (keys and
values in tags, roles in relations, usernames, etc.) as well as
metadata containing the precision of coordinates or timestamps in that
block.
A primitiveblock contains a sequence of primitive groups, each
containing primitives of the same type (nodes, densenodes, ways,
relations). Coordinates are stored in signed 64-bit integers. Lat&lon
are measured in units <granularity> nanodegrees. The default of
granularity of 100 nanodegrees corresponds to about 1cm on the ground,
and a full lat or lon fits into 32 bits.
Converting an integer to a lattitude or longitude uses the formula:
$OUT = IN * granularity / 10**9$. Many encoding schemes use delta
coding when representing nodes and relations.
*/
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/* Contains the file header. */
message HeaderBlock {
optional HeaderBBox bbox = 1;
/* Additional tags to aid in parsing this dataset */
repeated string required_features = 4;
repeated string optional_features = 5;
optional string writingprogram = 16;
optional string source = 17; // From the bbox field.
}
/** The bounding box field in the OSM header. BBOX, as used in the OSM
header. Units are always in nanodegrees -- they do not obey
granularity rules. */
message HeaderBBox {
required sint64 left = 1;
required sint64 right = 2;
required sint64 top = 3;
required sint64 bottom = 4;
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
message PrimitiveBlock {
required StringTable stringtable = 1;
repeated PrimitiveGroup primitivegroup = 2;
// Granularity, units of nanodegrees, used to store coordinates in this block
optional int32 granularity = 17 [default=100];
// Offset value between the output coordinates coordinates and the granularity grid in unites of nanodegrees.
optional int64 lat_offset = 19 [default=0];
optional int64 lon_offset = 20 [default=0];
// Granularity of dates, normally represented in units of milliseconds since the 1970 epoch.
optional int32 date_granularity = 18 [default=1000];
// Proposed extension:
//optional BBox bbox = 19;
}
// Group of OSMPrimitives. All primitives in a group must be the same type.
message PrimitiveGroup {
repeated Node nodes = 1;
optional DenseNodes dense = 2;
repeated Way ways = 3;
repeated Relation relations = 4;
repeated ChangeSet changesets = 5;
}
/** String table, contains the common strings in each block.
Note that we reserve index '0' as a delimiter, so the entry at that
index in the table is ALWAYS blank and unused.
*/
message StringTable {
repeated bytes s = 1;
}
/* Optional metadata that may be included into each primitive. */
message Info {
optional int32 version = 1 [default = -1];
optional int64 timestamp = 2;
optional int64 changeset = 3;
optional int32 uid = 4;
optional int32 user_sid = 5; // String IDs
}
/** Optional metadata that may be included into each primitive. Special dense format used in DenseNodes. */
message DenseInfo {
repeated int32 version = 1 [packed = true];
repeated sint64 timestamp = 2 [packed = true]; // DELTA coded
repeated sint64 changeset = 3 [packed = true]; // DELTA coded
repeated sint32 uid = 4 [packed = true]; // DELTA coded
repeated sint32 user_sid = 5 [packed = true]; // String IDs for usernames. DELTA coded
}
// THIS IS STUB DESIGN FOR CHANGESETS. NOT USED RIGHT NOW.
// TODO: REMOVE THIS?
message ChangeSet {
required int64 id = 1;
//
// // Parallel arrays.
// repeated uint32 keys = 2 [packed = true]; // String IDs.
// repeated uint32 vals = 3 [packed = true]; // String IDs.
//
// optional Info info = 4;
// optional int64 created_at = 8;
// optional int64 closetime_delta = 9;
// optional bool open = 10;
// optional HeaderBBox bbox = 11;
}
message Node {
required sint64 id = 1;
// Parallel arrays.
repeated uint32 keys = 2 [packed = true]; // String IDs.
repeated uint32 vals = 3 [packed = true]; // String IDs.
optional Info info = 4; // May be omitted in omitmeta
required sint64 lat = 8;
required sint64 lon = 9;
}
/* Used to densly represent a sequence of nodes that do not have any tags.
We represent these nodes columnwise as five columns: ID's, lats, and
lons, all delta coded. When metadata is not omitted,
We encode keys & vals for all nodes as a single array of integers
containing key-stringid and val-stringid, using a stringid of 0 as a
delimiter between nodes.
( (<keyid> <valid>)* '0' )*
*/
message DenseNodes {
repeated sint64 id = 1 [packed = true]; // DELTA coded
//repeated Info info = 4;
optional DenseInfo denseinfo = 5;
repeated sint64 lat = 8 [packed = true]; // DELTA coded
repeated sint64 lon = 9 [packed = true]; // DELTA coded
// Special packing of keys and vals into one array. May be empty if all nodes in this block are tagless.
repeated int32 keys_vals = 10 [packed = true];
}
message Way {
required int64 id = 1;
// Parallel arrays.
repeated uint32 keys = 2 [packed = true];
repeated uint32 vals = 3 [packed = true];
optional Info info = 4;
repeated sint64 refs = 8 [packed = true]; // DELTA coded
}
message Relation {
enum MemberType {
NODE = 0;
WAY = 1;
RELATION = 2;
}
required int64 id = 1;
// Parallel arrays.
repeated uint32 keys = 2 [packed = true];
repeated uint32 vals = 3 [packed = true];
optional Info info = 4;
// Parallel arrays
repeated int32 roles_sid = 8 [packed = true];
repeated sint64 memids = 9 [packed = true]; // DELTA encoded
repeated MemberType types = 10 [packed = true];
}