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