2 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
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
8 package org.opendaylight.protocol.bgp.mode.impl;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.annotations.Beta;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.collect.ImmutableSet.Builder;
15 import java.lang.reflect.Array;
16 import java.util.Arrays;
17 import java.util.Comparator;
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
23 * A map maintaining a set of values in an external array corresponding to a set of keys. This class is expected to be
24 * used as a template, i.e. users subclass it to a concrete map and use exclusively that class to access the
28 public abstract class AbstractOffsetMap<K extends Immutable & Comparable<K>, T extends AbstractOffsetMap<K, T>> {
29 private static final Logger LOG = LoggerFactory.getLogger(AbstractOffsetMap.class);
30 private static final String INVALIDOFFSET = "Invalid offset %s for %s router IDs";
32 private final K[] keys;
34 protected AbstractOffsetMap(final K[] emptyKeys, final Comparator<K> comparator, final ImmutableSet<K> routerIds) {
35 final K[] array = routerIds.toArray(emptyKeys);
36 Arrays.sort(array, comparator);
40 public final K getKey(final int offset) {
41 return this.keys[offset];
44 public final int offsetOf(final K key) {
45 return Arrays.binarySearch(keys, key, comparator());
48 public final boolean isEmpty() {
49 return keys.length == 0;
52 public final int size() {
56 public final T with(final K key) {
57 // TODO: we could make this faster if we had an array-backed Set and requiring
58 // the caller to give us the result of offsetOf() -- as that indicates
59 // where to insert the new routerId while maintaining the sorted nature
61 final Builder<K> builder = ImmutableSet.builderWithExpectedSize(size() + 1);
64 return instanceForKeys(builder.build());
67 public final T without(final K key) {
68 final ImmutableSet<K> set;
69 final int index = indexOf(key);
71 LOG.trace("Router key {} not found", key);
72 set = ImmutableSet.of();
74 set = ImmutableSet.copyOf(removeValue(keys, index, emptyKeys()));
76 return instanceForKeys(set);
79 public final <C> C getValue(final C[] array, final int offset) {
80 checkAccessOffest(offset);
84 public final <C> void setValue(final C[] array, final int offset, final C value) {
85 checkAccessOffest(offset);
86 array[offset] = value;
89 public final <C> C[] expand(final T oldOffsets, final C[] oldArray, final int offset) {
90 @SuppressWarnings("unchecked")
91 final C[] ret = (C[]) Array.newInstance(oldArray.getClass().getComponentType(), keys.length);
93 System.arraycopy(oldArray, 0, ret, 0, offset);
94 System.arraycopy(oldArray, offset, ret, offset + 1, oldOffsets.size() - offset);
98 public final <C> C[] removeValue(final C[] oldArray, final int offset, final C[] emptyArray) {
99 checkNegativeOffset(offset);
100 final int length = oldArray.length;
101 checkArgument(offset < keys.length, INVALIDOFFSET, offset, length);
103 final int newLength = length - 1;
104 if (newLength == 0) {
105 checkArgument(emptyArray.length == 0);
109 @SuppressWarnings("unchecked")
110 final C[] ret = (C[]) Array.newInstance(oldArray.getClass().getComponentType(), newLength);
111 System.arraycopy(oldArray, 0, ret, 0, offset);
112 if (offset < newLength) {
113 System.arraycopy(oldArray, offset + 1, ret, offset, newLength - offset);
119 protected abstract Comparator<K> comparator();
121 protected abstract K[] emptyKeys();
123 protected abstract T instanceForKeys(ImmutableSet<K> newKeys);
125 private int indexOf(final K key) {
126 for (int i = 0; i < keys.length; i++) {
127 if (key.equals(keys[i])) {
134 private void checkAccessOffest(final int offset) {
135 checkNegativeOffset(offset);
136 checkArgument(offset < keys.length, INVALIDOFFSET, offset, keys.length);
139 private static void checkNegativeOffset(final int offset) {
140 checkArgument(offset >= 0, "Invalid negative offset %s", offset);