ca30dd03ba4c714512e4708f61c81c5fe906b5d7
[yangtools.git] / model / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / PathFromRoot.java
1 /*
2  * Copyright (c) 2020 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.model.api;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.lang.invoke.MethodHandles;
13 import java.lang.invoke.VarHandle;
14 import java.util.AbstractList;
15 import java.util.ArrayDeque;
16 import java.util.Arrays;
17 import java.util.Deque;
18 import java.util.Iterator;
19 import java.util.Spliterator;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.yangtools.concepts.Immutable;
23 import org.opendaylight.yangtools.yang.common.QName;
24
25 final class PathFromRoot extends AbstractList<QName> implements Immutable {
26     private static final QName[] EMPTY_QNAMES = new QName[0];
27     private static final VarHandle QNAMES;
28
29     static {
30         try {
31             QNAMES = MethodHandles.lookup().findVarHandle(PathFromRoot.class, "qnames", QName[].class);
32         } catch (NoSuchFieldException | IllegalAccessException e) {
33             throw new ExceptionInInitializerError(e);
34         }
35     }
36
37     private final SchemaPath path;
38
39     @SuppressWarnings("unused")
40     private QName @Nullable [] qnames;
41
42     PathFromRoot(final SchemaPath path) {
43         this.path = requireNonNull(path);
44     }
45
46     @Override
47     public Iterator<QName> iterator() {
48         return Arrays.asList(qnames()).iterator();
49     }
50
51     @Override
52     public Spliterator<QName> spliterator() {
53         return Arrays.spliterator(qnames());
54     }
55
56     @Override
57     public QName get(final int index) {
58         return qnames()[index];
59     }
60
61     @Override
62     public boolean isEmpty() {
63         return false;
64     }
65
66     @Override
67     public int size() {
68         return qnames().length;
69     }
70
71     private QName @NonNull [] qnames() {
72         final QName[] local = (QName[]) QNAMES.getAcquire(this);
73         return local != null ? local : loadQNames();
74     }
75
76     private QName @NonNull [] loadQNames() {
77         final Deque<QName> tmp = new ArrayDeque<>();
78         for (QName qname : path.getPathTowardsRoot()) {
79             tmp.addFirst(qname);
80         }
81
82         final QName[] result = tmp.toArray(EMPTY_QNAMES);
83         // We do not care about atomicity here
84         QNAMES.setRelease(this, result);
85         return result;
86     }
87 }