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