diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe')
3 files changed, 162 insertions, 129 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodec.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodec.java new file mode 100644 index 0000000000..9be4046daf --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/ImmutableMapCodec.java @@ -0,0 +1,91 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.skyframe.serialization; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Ordering; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.CodedOutputStream; +import java.io.IOException; +import java.util.Comparator; +import java.util.Map; + +/** + * Encodes an {@link ImmutableMap}, which may be an ImmutableSortedMap. We handle both here because + * we cannot handle ImmutableSortedMap with any ordering other than the default, and so we degrade + * to ImmutableMap in that case, hoping that the caller does not notice. + */ +class ImmutableMapCodec implements ObjectCodec<ImmutableMap<?, ?>> { + @SuppressWarnings("unchecked") + @Override + public Class<ImmutableMap<?, ?>> getEncodedClass() { + // Because Java disallows converting from Class<ImmutableMap> to Class<ImmutableMap<?, ?>> + // directly. + return (Class<ImmutableMap<?, ?>>) ((Class<?>) ImmutableMap.class); + } + + @Override + public void serialize( + SerializationContext context, ImmutableMap<?, ?> map, CodedOutputStream codedOut) + throws SerializationException, IOException { + codedOut.writeInt32NoTag(map.size()); + boolean serializeAsSortedMap = false; + if (map instanceof ImmutableSortedMap) { + Comparator<?> comparator = ((ImmutableSortedMap<?, ?>) map).comparator(); + // In practice the comparator seems to always be Ordering.natural(), but be flexible. + serializeAsSortedMap = + comparator.equals(Ordering.natural()) || comparator.equals(Comparator.naturalOrder()); + } + codedOut.writeBoolNoTag(serializeAsSortedMap); + for (Map.Entry<?, ?> entry : map.entrySet()) { + context.serialize(entry.getKey(), codedOut); + context.serialize(entry.getValue(), codedOut); + } + } + + @Override + public ImmutableMap<?, ?> deserialize(DeserializationContext context, CodedInputStream codedIn) + throws SerializationException, IOException { + int length = codedIn.readInt32(); + if (length < 0) { + throw new SerializationException("Expected non-negative length: " + length); + } + if (codedIn.readBool()) { + return buildMap(ImmutableSortedMap.naturalOrder(), length, context, codedIn); + } else { + return buildMap(ImmutableMap.builderWithExpectedSize(length), length, context, codedIn); + } + } + + private static <T> ImmutableMap<T, Object> buildMap( + ImmutableMap.Builder<T, Object> builder, + int length, + DeserializationContext context, + CodedInputStream codedIn) + throws IOException, SerializationException { + for (int i = 0; i < length; i++) { + T key = context.deserialize(codedIn); + Object value = context.deserialize(codedIn); + builder.put(key, value); + } + try { + return builder.build(); + } catch (IllegalArgumentException e) { + throw new SerializationException( + "Duplicate keys during ImmutableMapCodec deserialization", e); + } + } +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/OptionalCodec.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/OptionalCodec.java new file mode 100644 index 0000000000..549b9a56ae --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/OptionalCodec.java @@ -0,0 +1,47 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.devtools.build.lib.skyframe.serialization; + +import com.google.common.base.Optional; +import com.google.protobuf.CodedInputStream; +import com.google.protobuf.CodedOutputStream; +import java.io.IOException; + +/** {@link ObjectCodec} for {@link Optional}. */ +class OptionalCodec implements ObjectCodec<Optional<?>> { + @SuppressWarnings("unchecked") + @Override + public Class<Optional<?>> getEncodedClass() { + return (Class<Optional<?>>) (Class<?>) Optional.class; + } + + @Override + public void serialize(SerializationContext context, Optional<?> obj, CodedOutputStream codedOut) + throws SerializationException, IOException { + codedOut.writeBoolNoTag(obj.isPresent()); + if (obj.isPresent()) { + context.serialize(obj.get(), codedOut); + } + } + + @Override + public Optional<?> deserialize(DeserializationContext context, CodedInputStream codedIn) + throws SerializationException, IOException { + if (!codedIn.readBool()) { + return Optional.absent(); + } + return Optional.of(context.deserialize(codedIn)); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java index af8a2da6bb..1ab908cfab 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java @@ -14,14 +14,11 @@ package com.google.devtools.build.lib.skyframe.serialization.autocodec; -import com.google.common.base.Optional; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -44,7 +41,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; -import java.util.function.Consumer; import java.util.regex.Pattern; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.ElementKind; @@ -422,31 +418,6 @@ class Marshallers { } }; - private final Marshaller optionalMarshaller = - new Marshaller() { - @Override - public boolean matches(DeclaredType type) { - return matchesErased(type, Optional.class); - } - - @Override - public void addSerializationCode(Context context) { - DeclaredType optionalType = - (DeclaredType) context.getDeclaredType().getTypeArguments().get(0); - writeSerializationCode(context.with(optionalType, context.name + ".orNull()")); - } - - @Override - public void addDeserializationCode(Context context) { - DeclaredType optionalType = - (DeclaredType) context.getDeclaredType().getTypeArguments().get(0); - String optionalName = context.makeName("optional"); - writeDeserializationCode(context.with(optionalType, optionalName)); - context.builder.addStatement( - "$L = $T.fromNullable($L)", context.name, Optional.class, optionalName); - } - }; - private final Marshaller uuidMarshller = new Marshaller() { @Override @@ -717,106 +688,33 @@ class Marshallers { @Override public void addDeserializationCode(Context context) { - addMapDeserializationCode( - context, - (builderName, key, value) -> - context.builder.addStatement( - "$T<$T, $T> $L = new $T<>()", - LinkedHashMap.class, - key.getTypeName(), - value.getTypeName(), - builderName, - LinkedHashMap.class), - (builderName) -> context.builder.addStatement("$L = $L", context.name, builderName)); - } - }; - - private final Marshaller immutableMapMarshaller = - new Marshaller() { - @Override - public boolean matches(DeclaredType type) { - return matchesErased(type, ImmutableMap.class); - } - - @Override - public void addSerializationCode(Context context) { - mapMarshaller.addSerializationCode(context); - } - - @Override - public void addDeserializationCode(Context context) { - addMapDeserializationCode( - context, - (builderName, key, value) -> - context.builder.addStatement( - "$T<$T, $T> $L = new $T<>()", - ImmutableMap.Builder.class, - key.getTypeName(), - value.getTypeName(), - builderName, - ImmutableMap.Builder.class), - (builderName) -> - context.builder.addStatement("$L = $L.build()", context.name, builderName)); - } - }; - - private final Marshaller immutableSortedMapMarshaller = - new Marshaller() { - @Override - public boolean matches(DeclaredType type) { - return matchesErased(type, ImmutableSortedMap.class); - } - - @Override - public void addSerializationCode(Context context) { - mapMarshaller.addSerializationCode(context); - } - - @Override - public void addDeserializationCode(Context context) { - addMapDeserializationCode( - context, - (builderName, key, value) -> - context.builder.addStatement( - "$T<$T, $T> $L = new $T<>($T.naturalOrder())", - ImmutableSortedMap.Builder.class, - key.getTypeName(), - value.getTypeName(), - builderName, - ImmutableSortedMap.Builder.class, - Comparator.class), - (builderName) -> - context.builder.addStatement("$L = $L.build()", context.name, builderName)); + String builderName = context.makeName("builder"); + Context key = + context.with( + context.getDeclaredType().getTypeArguments().get(0), context.makeName("key")); + Context value = + context.with( + context.getDeclaredType().getTypeArguments().get(1), context.makeName("value")); + context.builder.addStatement( + "$T<$T, $T> $L = new $T<>()", + LinkedHashMap.class, + key.getTypeName(), + value.getTypeName(), + builderName, + LinkedHashMap.class); + String lengthName = context.makeName("length"); + context.builder.addStatement("int $L = codedIn.readInt32()", lengthName); + String indexName = context.makeName("i"); + context.builder.beginControlFlow( + "for (int $L = 0; $L < $L; ++$L)", indexName, indexName, lengthName, indexName); + writeDeserializationCode(key); + writeDeserializationCode(value); + context.builder.addStatement("$L.put($L, $L)", builderName, key.name, value.name); + context.builder.endControlFlow(); + context.builder.addStatement("$L = $L", context.name, builderName); } }; - @FunctionalInterface - private static interface MapBuilderInitializer { - void initialize(String builderName, Context key, Context value); - } - - /** Helper for map marshallers. */ - private void addMapDeserializationCode( - Context context, MapBuilderInitializer mapBuilderInitializer, Consumer<String> finisher) { - String builderName = context.makeName("builder"); - Context key = - context.with(context.getDeclaredType().getTypeArguments().get(0), context.makeName("key")); - Context value = - context.with( - context.getDeclaredType().getTypeArguments().get(1), context.makeName("value")); - mapBuilderInitializer.initialize(builderName, key, value); - String lengthName = context.makeName("length"); - context.builder.addStatement("int $L = codedIn.readInt32()", lengthName); - String indexName = context.makeName("i"); - context.builder.beginControlFlow( - "for (int $L = 0; $L < $L; ++$L)", indexName, indexName, lengthName, indexName); - writeDeserializationCode(key); - writeDeserializationCode(value); - context.builder.addStatement("$L.put($L, $L)", builderName, key.name, value.name); - context.builder.endControlFlow(); - finisher.accept(builderName); - } - private final Marshaller multimapMarshaller = new Marshaller() { @Override @@ -1049,7 +947,6 @@ class Marshallers { enumMarshaller, stringMarshaller, charSequenceMarshaller, - optionalMarshaller, supplierMarshaller, uuidMarshller, mapEntryMarshaller, @@ -1057,8 +954,6 @@ class Marshallers { immutableSetMarshaller, immutableSortedSetMarshaller, mapMarshaller, - immutableMapMarshaller, - immutableSortedMapMarshaller, multimapMarshaller, nestedSetMarshaller, patternMarshaller, |