<commit_before>package com.openxc.measurements;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

import com.openxc.NoValueException;
import com.openxc.messages.NamedVehicleMessage;
import com.openxc.messages.SimpleVehicleMessage;
import com.openxc.messages.EventedSimpleVehicleMessage;
import com.openxc.messages.VehicleMessage;
import com.openxc.units.Unit;
import com.openxc.util.AgingData;
import com.openxc.util.Range;

import android.util.Log;

/**
 * The BaseMeasurement is the base implementation of the Measurement, and
 * wraps an instance of a {@link Unit}, and the value it returns is always
 * in terms of this Unit.
 *
 * The Unit wrapper might seem annoying at first, but it is critical to avoid
 * misinterpreting the unit and crashing your lander into Mars
 * (http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
 *
 * Most applications will not use this class directly, but will import specific
 * child classes that correspond to specific types of measurements - i.e. the
 * parameterized instances of this class with a Unit. That may seem like a
 * "psuedo-typedef" but we're using it to enforce the binding between
 * the measurement and its unit type. This unfortunately means we have to add
 * constructors to every child class because they aren't inherited from
 * Measurement. If you know of a better way, please say so.
 */
public class BaseMeasurement<TheUnit extends Unit> implements Measurement {
    private AgingData<TheUnit> mValue;
    private AgingData<Unit> mEvent;
    private Range<TheUnit> mRange;
    private static BiMap<String, Class<? extends Measurement>>
            sMeasurementIdToClass;

    static {
        sMeasurementIdToClass = HashBiMap.create();
    }

    /**
     * Construct a new Measurement with the given value.
     *
     * @param value the TheUnit this measurement represents.
     */
    public BaseMeasurement(TheUnit value) {
        mValue = new AgingData<TheUnit>(value);
    }

    public BaseMeasurement(TheUnit value, Unit event) {
        this(value);
        mEvent = new AgingData<Unit>(event);
    }

    /**
     * Construct an new Measurement with the given value and valid Range.
     *
     * There is not currently any automated verification that the value is
     * within the range - this is up to the application programmer.
     *
     * @param value the TheUnit this measurement represents.
     * @param range the valid {@link Range} of values for this measurement.
     */
    public BaseMeasurement(TheUnit value, Range<TheUnit> range) {
        this(value);
        mRange = range;
    }

    public void setTimestamp(long timestamp) {
        mValue.setTimestamp(timestamp);
    }

    public long getAge() {
        return mValue.getAge();
    }

    public long getBirthtime() {
        return mValue.getTimestamp();
    }

    public boolean hasRange() {
        return mRange != null;
    }

    public Range<TheUnit> getRange() throws NoRangeException {
        if(!hasRange()) {
            throw new NoRangeException();
        }
        return mRange;
    }

    public TheUnit getValue() {
        return mValue.getValue();
    }

    public boolean hasEvent() {
        return mEvent != null;
    }

    public Object getEvent() {
        if(hasEvent()) {
            return mEvent.getValue();
        }
        return null;
    }

    public Object getSerializedValue() {
        return getValue().getSerializedValue();
    }

    public Object getSerializedEvent() {
        return getEvent();
    }

    public VehicleMessage toVehicleMessage() {
        VehicleMessage message = null;
        if(hasEvent()) {
            message = new EventedSimpleVehicleMessage(mValue.getTimestamp(),
                    getGenericName(), getSerializedValue(),
                    getSerializedEvent());
        } else {
            message = new SimpleVehicleMessage(mValue.getTimestamp(),
                    getGenericName(), getSerializedValue());
        }
        return message;
    }

    public String getGenericName() {
        return "base_measurement";
    }

    private static void cacheMeasurementId(
            Class<? extends Measurement> measurementType)
            throws UnrecognizedMeasurementTypeException {
        String measurementId;
        try {
            measurementId = (String) measurementType.getField("ID").get(
                    measurementType);
            sMeasurementIdToClass.put(measurementId, measurementType);
        } catch(NoSuchFieldException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " doesn't have an ID field", e);
        } catch(IllegalAccessException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has an inaccessible " +
                    "ID field", e);
        }
    }

    public static String getIdForClass(
            Class<? extends Measurement> measurementType)
            throws UnrecognizedMeasurementTypeException {
        if(!sMeasurementIdToClass.inverse().containsKey(measurementType)) {
            cacheMeasurementId(measurementType);
        }
        return sMeasurementIdToClass.inverse().get(measurementType);
    }

    public static Class<? extends Measurement>
            getClassForId(String measurementId)
            throws UnrecognizedMeasurementTypeException {
        Class<? extends Measurement> result = sMeasurementIdToClass.get(
                measurementId);
        if(result == null) {
            throw new UnrecognizedMeasurementTypeException(
                    "Didn't have a measurement with ID " + measurementId +
                    " cached");
        }
        return result;
    }

    public static Measurement getMeasurementFromMessage(
            NamedVehicleMessage message)
            throws UnrecognizedMeasurementTypeException, NoValueException {
        Class<? extends Measurement> measurementClass =
            BaseMeasurement.getClassForId(message.getName());
        return BaseMeasurement.getMeasurementFromMessage(measurementClass,
                message);
    }

    public static Measurement getMeasurementFromMessage(
            Class<? extends Measurement> measurementType,
            NamedVehicleMessage message)
            throws UnrecognizedMeasurementTypeException, NoValueException {
        Constructor<? extends Measurement> constructor = null;
        if(message == null) {
            throw new NoValueException();
        }

        try {
            // TODO support EventedSimpleVehicleMessage
            if(message instanceof SimpleVehicleMessage) {
                SimpleVehicleMessage simpleMessage =
                        (SimpleVehicleMessage) message;
                Class<?> valueClass = simpleMessage.getValue().getClass();
                if(valueClass == Double.class || valueClass == Integer.class) {
                    valueClass = Number.class;
                }

                try {
                    constructor = measurementType.getConstructor(valueClass);
                } catch(NoSuchMethodException e) {
                    throw new UnrecognizedMeasurementTypeException(
                            measurementType +
                            " doesn't have the expected constructor, " +
                           measurementType + "(" +
                           valueClass + ")");
                }

                Measurement measurement = constructor.newInstance(
                        simpleMessage.getValue());
                if (simpleMessage.getTimestamp() != null) {
                    measurement.setTimestamp(simpleMessage.getTimestamp());
                }
                return measurement;
            } else {
                // TODO do we allow creating measurements from a generic values
                // map? need to make it public if so. i'm thinking that th
                // emeasurement should subclass simplevehiclemessage
                return null;
            }
        } catch(InstantiationException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " is abstract", e);
        } catch(IllegalAccessException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has a private constructor", e);
        } catch(IllegalArgumentException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has unexpected arguments", e);
        } catch(InvocationTargetException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + "'s constructor threw an exception",
                    e);
        }
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj) {
            return true;
        }

        if(obj == null) {
            return false;
        }

        if(getClass() != obj.getClass()) {
            return false;
        }

        @SuppressWarnings("unchecked")
        final BaseMeasurement<TheUnit> other = (BaseMeasurement<TheUnit>) obj;
        if(!other.getValue().equals(getValue())) {
            return false;
        }

        if(other.getEvent() != null && getEvent() != null) {
            if(!other.getEvent().equals(getEvent())) {
                return false;
            }
        } else if(other.getEvent() != getEvent()) {
            return false;
        }

        if(other.hasRange() != hasRange()) {
            return false;
        } else {
            try {
                if(!other.getRange().equals(getRange())) {
                    return false;
                }
            } catch(NoRangeException e) { }
        }

        return true;
    }

    @Override
    public String toString() {
        return getValue().toString();
    }
}
<commit_msg>Cache measurement IDs when a subclass is first constructed.<commit_after>package com.openxc.measurements;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

import com.openxc.NoValueException;
import com.openxc.messages.NamedVehicleMessage;
import com.openxc.messages.SimpleVehicleMessage;
import com.openxc.messages.EventedSimpleVehicleMessage;
import com.openxc.messages.VehicleMessage;
import com.openxc.units.Unit;
import com.openxc.util.AgingData;
import com.openxc.util.Range;

import android.util.Log;

/**
 * The BaseMeasurement is the base implementation of the Measurement, and
 * wraps an instance of a {@link Unit}, and the value it returns is always
 * in terms of this Unit.
 *
 * The Unit wrapper might seem annoying at first, but it is critical to avoid
 * misinterpreting the unit and crashing your lander into Mars
 * (http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
 *
 * Most applications will not use this class directly, but will import specific
 * child classes that correspond to specific types of measurements - i.e. the
 * parameterized instances of this class with a Unit. That may seem like a
 * "psuedo-typedef" but we're using it to enforce the binding between
 * the measurement and its unit type. This unfortunately means we have to add
 * constructors to every child class because they aren't inherited from
 * Measurement. If you know of a better way, please say so.
 */
public class BaseMeasurement<TheUnit extends Unit> implements Measurement {
    private static final String TAG = BaseMeasurement.class.toString();

    private AgingData<TheUnit> mValue;
    private AgingData<Unit> mEvent;
    private Range<TheUnit> mRange;
    private static BiMap<String, Class<? extends Measurement>>
            sMeasurementIdToClass;

    static {
        sMeasurementIdToClass = HashBiMap.create();
    }

    /**
     * Construct a new Measurement with the given value.
     *
     * @param value the TheUnit this measurement represents.
     */
    public BaseMeasurement(TheUnit value) {
        if(!sMeasurementIdToClass.inverse().containsKey(this.getClass())) {
            try {
                cacheMeasurementId(this.getClass());
            } catch(UnrecognizedMeasurementTypeException e) {
                Log.w(TAG, "Incomplete BaseMeasurement subclass", e);
            }
        }
        mValue = new AgingData<TheUnit>(value);
    }

    public BaseMeasurement(TheUnit value, Unit event) {
        this(value);
        mEvent = new AgingData<Unit>(event);
    }

    /**
     * Construct an new Measurement with the given value and valid Range.
     *
     * There is not currently any automated verification that the value is
     * within the range - this is up to the application programmer.
     *
     * @param value the TheUnit this measurement represents.
     * @param range the valid {@link Range} of values for this measurement.
     */
    public BaseMeasurement(TheUnit value, Range<TheUnit> range) {
        this(value);
        mRange = range;
    }

    public void setTimestamp(long timestamp) {
        mValue.setTimestamp(timestamp);
    }

    public long getAge() {
        return mValue.getAge();
    }

    public long getBirthtime() {
        return mValue.getTimestamp();
    }

    public boolean hasRange() {
        return mRange != null;
    }

    public Range<TheUnit> getRange() throws NoRangeException {
        if(!hasRange()) {
            throw new NoRangeException();
        }
        return mRange;
    }

    public TheUnit getValue() {
        return mValue.getValue();
    }

    public boolean hasEvent() {
        return mEvent != null;
    }

    public Object getEvent() {
        if(hasEvent()) {
            return mEvent.getValue();
        }
        return null;
    }

    public Object getSerializedValue() {
        return getValue().getSerializedValue();
    }

    public Object getSerializedEvent() {
        return getEvent();
    }

    public VehicleMessage toVehicleMessage() {
        VehicleMessage message = null;
        if(hasEvent()) {
            message = new EventedSimpleVehicleMessage(mValue.getTimestamp(),
                    getGenericName(), getSerializedValue(),
                    getSerializedEvent());
        } else {
            message = new SimpleVehicleMessage(mValue.getTimestamp(),
                    getGenericName(), getSerializedValue());
        }
        return message;
    }

    public String getGenericName() {
        return "base_measurement";
    }

    private static void cacheMeasurementId(
            Class<? extends Measurement> measurementType)
            throws UnrecognizedMeasurementTypeException {
        String measurementId;
        try {
            measurementId = (String) measurementType.getField("ID").get(
                    measurementType);
            sMeasurementIdToClass.put(measurementId, measurementType);
        } catch(NoSuchFieldException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " doesn't have an ID field", e);
        } catch(IllegalAccessException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has an inaccessible " +
                    "ID field", e);
        }
    }

    public static String getIdForClass(
            Class<? extends Measurement> measurementType)
            throws UnrecognizedMeasurementTypeException {
        if(!sMeasurementIdToClass.inverse().containsKey(measurementType)) {
            cacheMeasurementId(measurementType);
        }
        return sMeasurementIdToClass.inverse().get(measurementType);
    }

    public static Class<? extends Measurement>
            getClassForId(String measurementId)
            throws UnrecognizedMeasurementTypeException {
        Class<? extends Measurement> result = sMeasurementIdToClass.get(
                measurementId);
        if(result == null) {
            throw new UnrecognizedMeasurementTypeException(
                    "Didn't have a measurement with ID " + measurementId +
                    " cached");
        }
        return result;
    }

    public static Measurement getMeasurementFromMessage(
            NamedVehicleMessage message)
            throws UnrecognizedMeasurementTypeException, NoValueException {
        Class<? extends Measurement> measurementClass =
            BaseMeasurement.getClassForId(message.getName());
        return BaseMeasurement.getMeasurementFromMessage(measurementClass,
                message);
    }

    public static Measurement getMeasurementFromMessage(
            Class<? extends Measurement> measurementType,
            NamedVehicleMessage message)
            throws UnrecognizedMeasurementTypeException, NoValueException {
        Constructor<? extends Measurement> constructor = null;
        if(message == null) {
            throw new NoValueException();
        }

        try {
            // TODO support EventedSimpleVehicleMessage
            if(message instanceof SimpleVehicleMessage) {
                SimpleVehicleMessage simpleMessage =
                        (SimpleVehicleMessage) message;
                Class<?> valueClass = simpleMessage.getValue().getClass();
                if(valueClass == Double.class || valueClass == Integer.class) {
                    valueClass = Number.class;
                }

                try {
                    constructor = measurementType.getConstructor(valueClass);
                } catch(NoSuchMethodException e) {
                    throw new UnrecognizedMeasurementTypeException(
                            measurementType +
                            " doesn't have the expected constructor, " +
                           measurementType + "(" +
                           valueClass + ")");
                }

                Measurement measurement = constructor.newInstance(
                        simpleMessage.getValue());
                if (simpleMessage.getTimestamp() != null) {
                    measurement.setTimestamp(simpleMessage.getTimestamp());
                }
                return measurement;
            } else {
                // TODO do we allow creating measurements from a generic values
                // map? need to make it public if so. i'm thinking that th
                // emeasurement should subclass simplevehiclemessage
                return null;
            }
        } catch(InstantiationException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " is abstract", e);
        } catch(IllegalAccessException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has a private constructor", e);
        } catch(IllegalArgumentException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + " has unexpected arguments", e);
        } catch(InvocationTargetException e) {
            throw new UnrecognizedMeasurementTypeException(
                    measurementType + "'s constructor threw an exception",
                    e);
        }
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj) {
            return true;
        }

        if(obj == null) {
            return false;
        }

        if(getClass() != obj.getClass()) {
            return false;
        }

        @SuppressWarnings("unchecked")
        final BaseMeasurement<TheUnit> other = (BaseMeasurement<TheUnit>) obj;
        if(!other.getValue().equals(getValue())) {
            return false;
        }

        if(other.getEvent() != null && getEvent() != null) {
            if(!other.getEvent().equals(getEvent())) {
                return false;
            }
        } else if(other.getEvent() != getEvent()) {
            return false;
        }

        if(other.hasRange() != hasRange()) {
            return false;
        } else {
            try {
                if(!other.getRange().equals(getRange())) {
                    return false;
                }
            } catch(NoRangeException e) { }
        }

        return true;
    }

    @Override
    public String toString() {
        return getValue().toString();
    }
}

{'fraction_non_alphanumeric': 0.08077980750343744, 'fraction_numerical': 0.0, 'mean_word_length': 2.09922386242581, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3015425', 'n_tokens_mistral': 5032, 'n_tokens_neox': 4810, 'n_words': 1350}