view graal/com.oracle.max.base/src/com/sun/max/util/Enumerator.java @ 4222:8e2985cdaaa5

Renaming of VMExits and VMEntries part 3.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Wed, 04 Jan 2012 21:13:44 +0100
parents e233f5660da4
children
line wrap: on
line source

/*
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.max.util;

import java.util.*;

import com.sun.max.*;

/**
 * @see Enumerable
 */
public class Enumerator<E extends Enum<E> & Enumerable<E>>
    implements Symbolizer<E> {

    private final Class<E> type;
    private final E[] ordinalMap;
    private final E[] valueMap;
    private final int lowestValue;

    public Enumerator(Class<E> type) {
        this.type = type;
        ordinalMap = type.getEnumConstants();

        int lowValue = 0;
        int highestValue = ordinalMap.length - 1;
        boolean valuesAreSameAsOrdinals = true;
        for (E e : ordinalMap) {
            final int value = e.value();
            if (value != e.ordinal()) {
                valuesAreSameAsOrdinals = false;
            }
            if (value < lowValue) {
                lowValue = value;
            } else if (value > highestValue) {
                highestValue = value;
            }
        }

        if (valuesAreSameAsOrdinals) {
            this.lowestValue = 0;
            valueMap = ordinalMap;
        } else {
            final int valueMapLength = (highestValue - lowValue) + 1;
            final Class<E[]> arrayType = null;
            this.lowestValue = lowValue;
            valueMap = Utils.cast(arrayType, new Enum[valueMapLength]);
            for (E e : ordinalMap) {
                final int value = e.value();
                // The enumerable with the lowest ordinal is stored in the value map:
                if (valueMap[value] == null) {
                    valueMap[value] = e;
                }
            }
        }
    }

    public Class<E> type() {
        return type;
    }

    public int numberOfValues() {
        return ordinalMap.length;
    }

    /**
     * Adds all the enumerable constants in this enumerator to a given set.
     *
     * @param set
     *                the set to which the enumerable constants are to be added
     */
    public void addAll(Set<E> set) {
        for (E e : this) {
            set.add(e);
        }
    }

    public int size() {
        return ordinalMap.length;
    }

    public Iterator<E> iterator() {
        return Arrays.asList(ordinalMap).iterator();
    }

    /**
     * Gets the enumerable constant denoted by a given ordinal. Note that this differs from {@link #fromValue(int)} in
     * that the latter retrieves an enumerable constant matching a given {@linkplain Enumerable#value() value}. An
     * enumerable's value is not necessarily the same as its ordinal.
     *
     * @throws IndexOutOfBoundsException
     *                 if {@code 0 < ordinal || ordinal >= length()}
     */
    public E get(int ordinal) throws IndexOutOfBoundsException {
        return ordinalMap[ordinal];
    }

    /**
     * Gets the enumerable constant matching a given value. That is, this method gets an enumerable from this enumerator
     * whose {@linkplain Enumerable#value() value} is equal to {@code value}. Note that the given value may not match
     * any enumerable in this enumerator in which case null is returned. Additionally, there may be more than one
     * enumerable with a matching value in which case the matching enumerable with the lowest
     * {@linkplain Enum#ordinal() ordinal} is returned.
     */
    public E fromValue(int value) {
        final int index = value - lowestValue;
        if (index >= 0 && index < valueMap.length) {
            return valueMap[index];
        }
        return null;
    }
}