Use switch expressions for CopyType dispatch
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / EffectiveInstances.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.Map;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.yangtools.concepts.Mutable;
18 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
19 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStatementState;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /**
24  * Statement-reuse expansion of a single instance. The idea here is that a statement can end up being replicated the
25  * same way multiple times -- which does not typically happen, but when it does it is worth exploiting.
26  *
27  * @param <E> {@link EffectiveStatement} type
28  */
29 final class EffectiveInstances<E extends EffectiveStatement<?, ?>> implements Mutable {
30     private static final Logger LOG = LoggerFactory.getLogger(EffectiveInstances.class);
31
32     // Note on sizing: this fits three entries without expansion. Note we do not include the local copy, as it does
33     // not have the same original.
34     private final Map<EffectiveStatementState, E> copies = new HashMap<>(4);
35     private final @NonNull E local;
36
37     EffectiveInstances(final E local) {
38         this.local = requireNonNull(local);
39     }
40
41     @SuppressWarnings("unchecked")
42     static <E extends EffectiveStatement<?, ?>> @NonNull E local(final Object obj) {
43         return obj instanceof EffectiveInstances ? ((EffectiveInstances<E>) obj).local : requireNonNull((E) obj);
44     }
45
46     @NonNull E attachCopy(final @NonNull EffectiveStatementState key, @NonNull final E copy) {
47         final E prev = copies.putIfAbsent(requireNonNull(key), requireNonNull(copy));
48         if (prev == null) {
49             // Nothing matching state
50             return copy;
51         }
52
53         // We need to make sure substatements are actually the same. If they are not, we'll just return the copy,
54         // playing it safe.
55         final Collection<? extends EffectiveStatement<?, ?>> prevStmts = prev.effectiveSubstatements();
56         final Collection<? extends EffectiveStatement<?, ?>> copyStmts = copy.effectiveSubstatements();
57         if (prevStmts != copyStmts) {
58             if (prevStmts.size() != copyStmts.size()) {
59                 LOG.trace("Key {} substatement count mismatch", key);
60                 return copy;
61             }
62
63             final Iterator<? extends EffectiveStatement<?, ?>> prevIt = prevStmts.iterator();
64             final Iterator<? extends EffectiveStatement<?, ?>> copyIt = copyStmts.iterator();
65             while (prevIt.hasNext()) {
66                 if (prevIt.next() != copyIt.next()) {
67                     LOG.trace("Key {} substatement mismatch", key);
68                     return copy;
69                 }
70             }
71         }
72
73         LOG.trace("Key {} substatement reused", key);
74         return prev;
75     }
76 }