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

Commit d7c3a890 authored by Neil Fuller's avatar Neil Fuller
Browse files

Make ReferenceWithHistory output easier to use

Make ReferenceWithHistory easier to use by outputting a timestamp for
each set() operation, and providing a stable "set id" for historic
entries. This means consecutive dump() calls will assign the same ID to
the same historic entry, enabling easier comparison.

This doesn't change the contract of the storage, just the dump() output.

Test: treehugger
Bug: 149014708
Change-Id: I28919a25b09b70910873c40562b51fa6664103b0
parent 92ee6580
Loading
Loading
Loading
Loading
+21 −35
Original line number Diff line number Diff line
@@ -19,8 +19,11 @@ package com.android.server.timezonedetector;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;

import java.time.Duration;
import java.util.ArrayDeque;

/**
@@ -49,18 +52,15 @@ import java.util.ArrayDeque;
 */
public final class ReferenceWithHistory<V> {

    private static final Object NULL_MARKER = "{null marker}";

    /** The maximum number of references to store. */
    private final int mMaxHistorySize;

    /**
     * The history storage. Note that ArrayDeque doesn't support {@code null} so this stores Object
     * and not V. Use {@link #packNullIfRequired(Object)} and {@link #unpackNullIfRequired(Object)}
     * to convert to / from the storage object.
     */
    /** The number of times {@link #set(Object)} has been called. */
    private int mSetCount;

    /** The history storage. */
    @Nullable
    private ArrayDeque<Object> mValues;
    private ArrayDeque<TimestampedValue<V>> mValues;

    /**
     * Creates an instance that records, at most, the specified number of values.
@@ -78,8 +78,8 @@ public final class ReferenceWithHistory<V> {
        if (mValues == null || mValues.isEmpty()) {
            return null;
        }
        Object value = mValues.getFirst();
        return unpackNullIfRequired(value);
        TimestampedValue<V> valueHolder = mValues.getFirst();
        return valueHolder.getValue();
    }

    /**
@@ -98,8 +98,10 @@ public final class ReferenceWithHistory<V> {

        V previous = get();

        Object nullSafeValue = packNullIfRequired(newValue);
        mValues.addFirst(nullSafeValue);
        TimestampedValue<V> valueHolder =
                new TimestampedValue<>(SystemClock.elapsedRealtime(), newValue);
        mValues.addFirst(valueHolder);
        mSetCount++;
        return previous;
    }

@@ -110,10 +112,13 @@ public final class ReferenceWithHistory<V> {
        if (mValues == null) {
            ipw.println("{Empty}");
        } else {
            int i = 0;
            for (Object value : mValues) {
                ipw.println(i + ": " + unpackNullIfRequired(value));
                i++;
            int i = mSetCount;
            for (TimestampedValue<V> valueHolder : mValues) {
                ipw.print(--i);
                ipw.print("@");
                ipw.print(Duration.ofMillis(valueHolder.getReferenceTimeMillis()).toString());
                ipw.print(": ");
                ipw.println(valueHolder.getValue());
            }
        }
        ipw.flush();
@@ -130,23 +135,4 @@ public final class ReferenceWithHistory<V> {
    public String toString() {
        return String.valueOf(get());
    }

    /**
     * Turns a non-nullable Object into a nullable value. See also
     * {@link #packNullIfRequired(Object)}.
     */
    @SuppressWarnings("unchecked")
    @Nullable
    private V unpackNullIfRequired(@NonNull Object value) {
        return value == NULL_MARKER ? null : (V) value;
    }

    /**
     * Turns a nullable value into a non-nullable Object. See also
     * {@link #unpackNullIfRequired(Object)}.
     */
    @NonNull
    private Object packNullIfRequired(@Nullable V value) {
        return value == null ? NULL_MARKER : value;
    }
}