/* * Copyright 2015-present Facebook, Inc. * * 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.facebook.buck.rules.keys; /** * A wrapper of {@link RuleKeyHasher} that provides scoped hashing facilities. * * <p>Important: Container, wrapper and key signatures only get hashed if their scope was non-empty. * I.e. if at least one thing gets hashed under their scope. This is to support rule key builders * that ignore some fields. */ public class RuleKeyScopedHasher<HASH> { private final CountingRuleKeyHasher<HASH> hasher; public RuleKeyScopedHasher(CountingRuleKeyHasher<HASH> hasher) { this.hasher = hasher; } public CountingRuleKeyHasher<HASH> getHasher() { return hasher; } /** Hashes the key iff non-empty (i.e. if anything gets hashed during its scope). */ public Scope keyScope(final String key) { final long hasherCount = hasher.getCount(); return () -> { if (hasher.getCount() > hasherCount) { hasher.putKey(key); } }; } /** Hashes the wrapper iff non-empty (i.e. if any element gets hashed during its scope). */ public Scope wrapperScope(final RuleKeyHasher.Wrapper wrapper) { final long hasherCount = hasher.getCount(); return () -> { if (hasher.getCount() > hasherCount) { hasher.putWrapper(wrapper); } }; } /** * Hashes the container iff non-empty (i.e. if any element gets hashed during its scope). * * <p>Note that an element scope needs to be created for each element! */ public ContainerScope containerScope(final RuleKeyHasher.Container container) { return new ContainerScope(hasher, container); } public static class ContainerScope implements AutoCloseable { private final CountingRuleKeyHasher<?> hasher; private final RuleKeyHasher.Container container; private int elementCount = 0; private ContainerScope(CountingRuleKeyHasher<?> hasher, RuleKeyHasher.Container container) { this.hasher = hasher; this.container = container; } /** Increases element count if anything gets hashed during the element scope. */ public Scope elementScope() { final long hasherCount = hasher.getCount(); return () -> { if (hasher.getCount() > hasherCount) { elementCount++; } }; } /** Hashes the container iff non-empty (i.e. if any element gets hashed during this scope). */ @Override public void close() { if (elementCount > 0) { hasher.putContainer(container, elementCount); } } } public interface Scope extends AutoCloseable { @Override void close(); } }