/*
* Copyright 2016 LINE Corporation
*
* LINE Corporation licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.linecorp.armeria.common.logging;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.google.common.collect.Iterators;
import com.google.common.math.IntMath;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
/**
* A special {@link Set} implementation that pre-populates all possible combinations of
* {@link RequestLogAvailability}. Note that the number of all combinations are very small, because most
* combinations can be merged. e.g. [ REQUEST_START, SCHEME ] and [ SCHEME ] are same because their
* getterFlags are identical.
*/
final class RequestLogAvailabilitySet extends AbstractSet<RequestLogAvailability> {
private static final Int2ObjectMap<RequestLogAvailabilitySet> map = new Int2ObjectOpenHashMap<>();
static {
// Pre-populate all possible instances.
final RequestLogAvailability[] values = RequestLogAvailability.values();
final int end = IntMath.pow(2, values.length);
for (int i = 0; i < end; i++) {
int flags = 0;
for (RequestLogAvailability v : values) {
if ((i & 1 << v.ordinal()) != 0) {
flags |= v.setterFlags();
}
}
if (map.containsKey(flags)) {
continue;
}
map.put(flags, new RequestLogAvailabilitySet(flags));
}
}
static RequestLogAvailabilitySet of(int flags) {
final RequestLogAvailabilitySet availabilities = map.get(flags);
assert availabilities != null;
return availabilities;
}
private final int flags;
private final RequestLogAvailability[] values;
private RequestLogAvailabilitySet(int flags) {
this.flags = flags;
final List<RequestLogAvailability> values = new ArrayList<>();
for (RequestLogAvailability v : RequestLogAvailability.values()) {
if ((flags & v.getterFlags()) == v.getterFlags()) {
values.add(v);
}
}
this.values = values.toArray(new RequestLogAvailability[values.size()]);
}
@Override
public Iterator<RequestLogAvailability> iterator() {
return Iterators.forArray(values);
}
@Override
public int size() {
return values.length;
}
@Override
public boolean contains(Object e) {
if (!(e instanceof RequestLogAvailability)) {
return false;
}
final int flags = ((RequestLogAvailability) e).getterFlags();
return (this.flags & flags) == flags;
}
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public String toString() {
return Arrays.toString(values);
}
}