5b0e1340dd40a7e96d3b40540ad075cf765ed3ca
[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
18 @Beta
19 public final class CopyHistory implements Immutable {
20     private static final CopyType[] VALUES = CopyType.values();
21
22     private static final CopyHistory[][] CACHE = new CopyHistory[VALUES.length][];
23
24     static {
25         /*
26          * Cache size is dependent on number of items in CopyType, it costs N * 2^N objects.
27          * For 4 types that boils down to 4 * 16 = 64 objects.
28          * For 5 types that boils down to 5 * 32 = 160 objects.
29          * For 6 types that boils down to 6 * 64 = 384 objects.
30          *
31          * If we ever hit 6 types, the caching strategy needs to be revisited.
32          */
33         Verify.verify(VALUES.length < 6);
34     }
35
36     private static final CopyHistory ORIGINAL = cacheObject(CopyType.ORIGINAL, CopyType.ORIGINAL.bit());
37
38     private final short operations;
39     private final short lastOperation;
40
41     private CopyHistory(final int operations, final CopyType lastOperation) {
42         this.operations = (short) operations;
43         this.lastOperation = (short) lastOperation.ordinal();
44     }
45
46     public static CopyHistory original() {
47         return ORIGINAL;
48     }
49
50     public static CopyHistory of(final CopyType copyType, final CopyHistory copyHistory) {
51         return ORIGINAL.append(copyType, copyHistory);
52     }
53
54     private static CopyHistory[] cacheArray(final CopyType lastOperation) {
55         final int ordinal = lastOperation.ordinal();
56         CopyHistory[] ret = CACHE[ordinal];
57         if (ret == null) {
58             synchronized (CACHE) {
59                 ret = CACHE[ordinal];
60                 if (ret == null) {
61                     ret = new CopyHistory[1 << VALUES.length];
62                     CACHE[ordinal] = ret;
63                 }
64             }
65         }
66
67         return ret;
68     }
69
70     private static CopyHistory cacheObject(final CopyType lastOperation, final int operations) {
71         final CopyHistory[] array = cacheArray(lastOperation);
72         CopyHistory ret = array[operations];
73         if (ret == null) {
74             synchronized (array) {
75                 ret = array[operations];
76                 if (ret == null) {
77                     ret = new CopyHistory(operations, lastOperation);
78                     array[operations] = ret;
79                 }
80             }
81         }
82
83         return ret;
84     }
85
86     public boolean contains(final CopyType type) {
87         return (operations & type.bit()) != 0;
88     }
89
90     public CopyType getLastOperation() {
91         return VALUES[lastOperation];
92     }
93
94     @VisibleForTesting
95     CopyHistory append(final CopyType typeOfCopy, final CopyHistory toAppend) {
96         final int newOperations = operations | toAppend.operations | typeOfCopy.bit();
97         if (newOperations == operations && typeOfCopy.ordinal() == lastOperation) {
98             return this;
99         }
100
101         return cacheObject(typeOfCopy, newOperations);
102     }
103
104     @Override
105     public int hashCode() {
106         return Integer.hashCode(operations | lastOperation << Short.SIZE);
107     }
108
109     @Override
110     public boolean equals(final Object obj) {
111         if (obj == this) {
112             return true;
113         }
114         if (!(obj instanceof CopyHistory)) {
115             return false;
116         }
117         final CopyHistory other = (CopyHistory) obj;
118         return operations == other.operations && lastOperation == other.lastOperation;
119     }
120
121     @Override
122     public String toString() {
123         return MoreObjects.toStringHelper(this).add("lastOperation", getLastOperation())
124                 .add("operations", Arrays.stream(VALUES).filter(value -> (value.bit() & operations) != 0)
125                     .collect(Collectors.toList()))
126                 .toString();
127     }
128 }