/* * Copyright (C) 2016 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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 org.civilian.type.fn; import org.civilian.type.Type; import org.civilian.util.Check; /** * TypeMap is a helper class which allows to map a type to another * object. These Mappings can be established: * - for a single type: Type t -> value * - for a type family: Type.Category -> value * - for a default value: any type -> value */ public class TypeMap { public class Builder<T> { private Builder(Object value) { value_ = value; } public Builder<T> on(Type<? extends T> type) { set(type, value_); return this; } public Builder<T> on(Type.Category category) { set(category, value_); return this; } public Builder<T> byDefault() { setDefault(value_); return this; } private Object value_; } @SuppressWarnings("unchecked") public <VALUE> VALUE get(Type<?> type) { Check.notNull(type, "type"); Object v = null; int n = type.ordinal(); if (n < typeValues_.length) v = typeValues_[n]; if ((v == null) && ((n = type.category().ordinal()) < categoryValues_.length)) v = categoryValues_[n]; return (VALUE)(v != null ? v : defaultValue_); } public void set(Type<?> type, Object value) { Check.notNull(type, "type"); typeValues_ = set(typeValues_, type.ordinal(), value); } public void set(Type.Category category, Object value) { Check.notNull(category, "category"); categoryValues_ = set(categoryValues_, category.ordinal(), value); } private Object[] set(Object[] array, int n, Object value) { if (n >= array.length) { int newLen = 1 + n; Object[] newArray = new Object[newLen]; System.arraycopy(array, 0, newArray, 0, array.length); array = newArray; } array[n] = value; return array; } public void setDefault(Object newDefault) { defaultValue_ = newDefault; } public <T> Builder<T> use(Object value) { return new Builder<>(value); } private Object[] typeValues_ = EMPTY_VALUES; private Object[] categoryValues_ = EMPTY_VALUES; private Object defaultValue_; private static Object[] EMPTY_VALUES = new Object[0]; }