Un-deprecate CopyableNode, AddedByUsesAware
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / CopyHistory.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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.spi.meta;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.MoreObjects;
13 import com.google.common.base.Verify;
14 import java.util.Arrays;
15 import java.util.stream.Collectors;
16 import org.opendaylight.yangtools.concepts.Immutable;
17 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
18
19 @Beta
20 public final class CopyHistory implements Immutable, CopyableNode {
21     private static final CopyType[] VALUES = CopyType.values();
22
23     private static final CopyHistory[][] CACHE = new CopyHistory[VALUES.length][];
24
25     static {
26         /*
27          * Cache size is dependent on number of items in CopyType, it costs N * 2^N objects.
28          * For 4 types that boils down to 4 * 16 = 64 objects.
29          * For 5 types that boils down to 5 * 32 = 160 objects.
30          * For 6 types that boils down to 6 * 64 = 384 objects.
31          *
32          * If we ever hit 6 types, the caching strategy needs to be revisited.
33          */
34         Verify.verify(VALUES.length < 6);
35     }
36
37     private static final CopyHistory ORIGINAL = cacheObject(CopyType.ORIGINAL, CopyType.ORIGINAL.bit());
38     private static final int IS_ADDED_BY_USES_BITS =
39         CopyType.ADDED_BY_USES_AUGMENTATION.bit() | CopyType.ADDED_BY_USES.bit();
40     private static final int IS_AUGMENTING_BITS =
41         CopyType.ADDED_BY_USES_AUGMENTATION.bit() | CopyType.ADDED_BY_AUGMENTATION.bit();
42
43     private final short operations;
44     private final short lastOperation;
45
46     private CopyHistory(final int operations, final CopyType lastOperation) {
47         this.operations = (short) operations;
48         this.lastOperation = (short) lastOperation.ordinal();
49     }
50
51     public static CopyHistory original() {
52         return ORIGINAL;
53     }
54
55     public static CopyHistory of(final CopyType copyType, final CopyHistory copyHistory) {
56         return ORIGINAL.append(copyType, copyHistory);
57     }
58
59     private static CopyHistory[] cacheArray(final CopyType lastOperation) {
60         final int ordinal = lastOperation.ordinal();
61         CopyHistory[] ret = CACHE[ordinal];
62         if (ret == null) {
63             synchronized (CACHE) {
64                 ret = CACHE[ordinal];
65                 if (ret == null) {
66                     ret = new CopyHistory[1 << VALUES.length];
67                     CACHE[ordinal] = ret;
68                 }
69             }
70         }
71
72         return ret;
73     }
74
75     private static CopyHistory cacheObject(final CopyType lastOperation, final int operations) {
76         final CopyHistory[] array = cacheArray(lastOperation);
77         CopyHistory ret = array[operations];
78         if (ret == null) {
79             synchronized (array) {
80                 ret = array[operations];
81                 if (ret == null) {
82                     ret = new CopyHistory(operations, lastOperation);
83                     array[operations] = ret;
84                 }
85             }
86         }
87
88         return ret;
89     }
90
91     @VisibleForTesting
92     // FIXME: 7.0.0: hide this method
93     public boolean contains(final CopyType type) {
94         return (operations & type.bit()) != 0;
95     }
96
97     public CopyType getLastOperation() {
98         return VALUES[lastOperation];
99     }
100
101     @Override
102     public boolean isAugmenting() {
103         return (operations & IS_AUGMENTING_BITS) != 0;
104     }
105
106     @Override
107     public boolean isAddedByUses() {
108         return (operations & IS_ADDED_BY_USES_BITS) != 0;
109     }
110
111     @VisibleForTesting
112     CopyHistory append(final CopyType typeOfCopy, final CopyHistory toAppend) {
113         final int newOperations = operations | toAppend.operations | typeOfCopy.bit();
114         if (newOperations == operations && typeOfCopy.ordinal() == lastOperation) {
115             return this;
116         }
117
118         return cacheObject(typeOfCopy, newOperations);
119     }
120
121     @Override
122     public int hashCode() {
123         return Integer.hashCode(operations | lastOperation << Short.SIZE);
124     }
125
126     @Override
127     public boolean equals(final Object obj) {
128         if (obj == this) {
129             return true;
130         }
131         if (!(obj instanceof CopyHistory)) {
132             return false;
133         }
134         final CopyHistory other = (CopyHistory) obj;
135         return operations == other.operations && lastOperation == other.lastOperation;
136     }
137
138     @Override
139     public String toString() {
140         return MoreObjects.toStringHelper(this).add("lastOperation", getLastOperation())
141                 .add("operations", Arrays.stream(VALUES).filter(value -> (value.bit() & operations) != 0)
142                     .collect(Collectors.toList()))
143                 .toString();
144     }
145 }