Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b6d40027 authored by Adam Bookatz's avatar Adam Bookatz Committed by Automerger Merge Worker
Browse files

Merge "SparseDoubleArray" into sc-dev am: 6b8c61c8

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13921467

Change-Id: Icbcd25a1e469d7f1af473d1099ad9c266d86d39b
parents f5de8b7f 6b8c61c8
Loading
Loading
Loading
Loading
+166 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed 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 android.util;

/**
 * SparseDoubleArrays map integers to doubles.  Unlike a normal array of doubles,
 * there can be gaps in the indices.  It is intended to be more memory efficient
 * than using a HashMap to map Integers to Doubles, both because it avoids
 * auto-boxing keys and values and its data structure doesn't rely on an extra entry object
 * for each mapping.
 *
 * <p>Note that this container keeps its mappings in an array data structure,
 * using a binary search to find keys.  The implementation is not intended to be appropriate for
 * data structures
 * that may contain large numbers of items.  It is generally slower than a traditional
 * HashMap, since lookups require a binary search and adds and removes require inserting
 * and deleting entries in the array.  For containers holding up to hundreds of items,
 * the performance difference is not significant, less than 50%.</p>
 *
 * <p>It is possible to iterate over the items in this container using
 * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
 * <code>keyAt(int)</code> with ascending values of the index will return the
 * keys in ascending order, or the values corresponding to the keys in ascending
 * order in the case of <code>valueAt(int)</code>.</p>
 *
 * @see SparseLongArray
 *
 * @hide
 */
public class SparseDoubleArray implements Cloneable {
    /**
     * The int->double map, but storing the doubles as longs using
     * {@link Double#doubleToRawLongBits(double)}.
     */
    private SparseLongArray mValues;

    /** Creates a new SparseDoubleArray containing no mappings. */
    public SparseDoubleArray() {
        this(10);
    }

    /**
     * Creates a new SparseDoubleArray, containing no mappings, that will not
     * require any additional memory allocation to store the specified
     * number of mappings.  If you supply an initial capacity of 0, the
     * sparse array will be initialized with a light-weight representation
     * not requiring any additional array allocations.
     */
    public SparseDoubleArray(int initialCapacity) {
        mValues = new SparseLongArray(initialCapacity);
    }

    @Override
    public SparseDoubleArray clone() {
        SparseDoubleArray clone = null;
        try {
            clone = (SparseDoubleArray) super.clone();
            clone.mValues = mValues.clone();
        } catch (CloneNotSupportedException cnse) {
            /* ignore */
        }
        return clone;
    }

    /**
     * Gets the double mapped from the specified key, or <code>0</code>
     * if no such mapping has been made.
     */
    public double get(int key) {
        final int index = mValues.indexOfKey(key);
        if (index < 0) {
            return 0.0d;
        }
        return valueAt(index);
    }

    /**
     * Adds a mapping from the specified key to the specified value,
     * replacing the previous mapping from the specified key if there
     * was one.
     */
    public void put(int key, double value) {
        mValues.put(key, Double.doubleToRawLongBits(value));
    }

    /**
     * Adds a mapping from the specified key to the specified value,
     * <b>adding</b> its value to the previous mapping from the specified key if there
     * was one.
     *
     * <p>This differs from {@link #put} because instead of replacing any previous value, it adds
     * (in the numerical sense) to it.
     */
    public void add(int key, double summand) {
        final double oldValue = get(key);
        put(key, oldValue + summand);
    }

    /** Returns the number of key-value mappings that this SparseDoubleArray currently stores. */
    public int size() {
        return mValues.size();
    }

    /**
     * Given an index in the range <code>0...size()-1</code>, returns
     * the key from the <code>index</code>th key-value mapping that this
     * SparseDoubleArray stores.
     *
     * @see SparseLongArray#keyAt(int)
     */
    public int keyAt(int index) {
        return mValues.keyAt(index);
    }

    /**
     * Given an index in the range <code>0...size()-1</code>, returns
     * the value from the <code>index</code>th key-value mapping that this
     * SparseDoubleArray stores.
     *
     * @see SparseLongArray#valueAt(int)
     */
    public double valueAt(int index) {
        return Double.longBitsToDouble(mValues.valueAt(index));
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation composes a string by iterating over its mappings.
     */
    @Override
    public String toString() {
        if (size() <= 0) {
            return "{}";
        }

        StringBuilder buffer = new StringBuilder(size() * 34);
        buffer.append('{');
        for (int i = 0; i < size(); i++) {
            if (i > 0) {
                buffer.append(", ");
            }
            int key = keyAt(i);
            buffer.append(key);
            buffer.append('=');
            double value = valueAt(i);
            buffer.append(value);
        }
        buffer.append('}');
        return buffer.toString();
    }
}
+1 −75
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseDoubleArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
@@ -12547,81 +12548,6 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }
    /**
     * SparseDoubleArray map integers to doubles.
     * Its implementation is the same as that of {@link SparseLongArray}; see there for details.
     *
     * @see SparseLongArray
     */
    private static class SparseDoubleArray {
        /**
         * The int->double map, but storing the doubles as longs using
         * {@link Double.doubleToRawLongBits(double)}.
         */
        private final SparseLongArray mValues = new SparseLongArray();
        /**
         * Gets the double mapped from the specified key, or <code>0</code>
         * if no such mapping has been made.
         */
        public double get(int key) {
            if (mValues.indexOfKey(key) >= 0) {
                return Double.longBitsToDouble(mValues.get(key));
            }
            return 0;
        }
        /**
         * Adds a mapping from the specified key to the specified value,
         * replacing the previous mapping from the specified key if there
         * was one.
         */
        public void put(int key, double value) {
            mValues.put(key, Double.doubleToRawLongBits(value));
        }
        /**
         * Adds a mapping from the specified key to the specified value,
         * <b>adding</b> to the previous mapping from the specified key if there
         * was one.
         */
        public void add(int key, double summand) {
            final double oldValue = get(key);
            put(key, oldValue + summand);
        }
        /**
         * Returns the number of key-value mappings that this SparseDoubleArray
         * currently stores.
         */
        public int size() {
            return mValues.size();
        }
        /**
         * Given an index in the range <code>0...size()-1</code>, returns
         * the key from the <code>index</code>th key-value mapping that this
         * SparseDoubleArray stores.
         *
         * @see SparseLongArray#keyAt(int)
         */
        public int keyAt(int index) {
            return mValues.keyAt(index);
        }
        /**
         * Given an index in the range <code>0...size()-1</code>, returns
         * the value from the <code>index</code>th key-value mapping that this
         * SparseDoubleArray stores.
         *
         * @see SparseLongArray#valueAt(int)
         */
        public double valueAt(int index) {
            return Double.longBitsToDouble(mValues.valueAt(index));
        }
    }
    /**
     * Read and record Rail Energy data.
     */
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed 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 android.util;

import static org.junit.Assert.assertEquals;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;

/**
 * Internal tests for {@link SparseDoubleArray}.
 *
 * Run using:
 *  atest FrameworksCoreTests:android.util.SparseDoubleArrayTest
 */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SparseDoubleArrayTest {
    private static final double EXACT_PRECISION = 0;
    private static final double PRECISION = 0.000000001;

    @Test
    public void testPutGet() {
        final SparseDoubleArray sda = new SparseDoubleArray();
        assertEquals("Array should be empty", 0, sda.size());

        final int[] keys = {1, 6, -14, 53251, 5, -13412, 12, 0, 2};
        final double[] values = {7, -12.4, 7, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
                Double.NaN,
                4311236312.0 / 3431470161413514334123.0,
                431123636434132151313412.0 / 34323.0,
                0};
        for (int i = 0; i < keys.length; i++) {
            sda.put(keys[i], values[i]);
        }

        assertEquals("Wrong size array", keys.length, sda.size());
        // Due to the implementation, we actually expect EXACT double equality.
        for (int i = 0; i < keys.length; i++) {
            assertEquals("Wrong value at index " + i, values[i], sda.get(keys[i]), EXACT_PRECISION);
        }

        // Now check something that was never put in
        assertEquals("Wrong value for absent index", 0, sda.get(100000), EXACT_PRECISION);
    }

    @Test
    public void testAdd() {
        final SparseDoubleArray sda = new SparseDoubleArray();

        sda.put(4, 6.1);
        sda.add(4, -1.2);
        sda.add(2, -1.2);

        assertEquals(6.1 - 1.2, sda.get(4), PRECISION);
        assertEquals(-1.2, sda.get(2), PRECISION);
    }

    @Test
    public void testKeyValueAt() {
        final SparseDoubleArray sda = new SparseDoubleArray();

        final int[] keys = {1, 6, -14, 53251, 5, -13412, 12, 0, 2};
        final double[] values = {7, -12.4, 7, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
                Double.NaN,
                4311236312.0 / 3431470161413514334123.0,
                431123636434132151313412.0 / 34323.0,
                0};
        for (int i = 0; i < keys.length; i++) {
            sda.put(keys[i], values[i]);
        }

        // Sort the sample data.
        final ArrayMap<Integer, Double> map = new ArrayMap<>(keys.length);
        for (int i = 0; i < keys.length; i++) {
            map.put(keys[i], values[i]);
        }
        final int[] sortedKeys = Arrays.copyOf(keys, keys.length);
        Arrays.sort(sortedKeys);

        for (int i = 0; i < sortedKeys.length; i++) {
            final int expectedKey = sortedKeys[i];
            final double expectedValue = map.get(expectedKey);

            assertEquals("Wrong key at index " + i, expectedKey, sda.keyAt(i), PRECISION);
            assertEquals("Wrong value at index " + i, expectedValue, sda.valueAt(i), PRECISION);
        }
    }
}