Loading libs/battery/LongArrayMultiStateCounter.cpp +110 −34 Original line number Diff line number Diff line Loading @@ -21,58 +21,134 @@ namespace android { namespace battery { template <> bool LongArrayMultiStateCounter::delta(const std::vector<uint64_t>& previousValue, const std::vector<uint64_t>& newValue, std::vector<uint64_t>* outValue) const { size_t size = previousValue.size(); if (newValue.size() != size) { ALOGE("Incorrect array size: %d, should be %d", (int)newValue.size(), (int)size); return false; Uint64ArrayRW::Uint64ArrayRW(const Uint64Array ©) : Uint64Array(copy.size()) { if (mSize != 0 && copy.data() != nullptr) { mData = new uint64_t[mSize]; memcpy(mData, copy.data(), mSize * sizeof(uint64_t)); } else { mData = nullptr; } } bool is_delta_valid = true; for (int i = size - 1; i >= 0; i--) { if (newValue[i] >= previousValue[i]) { (*outValue)[i] = newValue[i] - previousValue[i]; uint64_t *Uint64ArrayRW::dataRW() { if (mData == nullptr) { mData = new uint64_t[mSize]; memset(mData, 0, mSize * sizeof(uint64_t)); } return mData; } Uint64ArrayRW &Uint64ArrayRW::operator=(const Uint64Array &t) { if (t.size() != mSize) { delete[] mData; mSize = t.size(); mData = nullptr; } if (mSize != 0) { if (t.data() != nullptr) { mData = new uint64_t[mSize]; memcpy(mData, t.data(), mSize * sizeof(uint64_t)); } else { (*outValue)[i] = 0; is_delta_valid = false; mData = nullptr; } } return is_delta_valid; return *this; } std::ostream &operator<<(std::ostream &os, const Uint64Array &v) { os << "{"; const uint64_t *data = v.data(); if (data != nullptr) { bool first = true; for (size_t i = 0; i < v.size(); i++) { if (!first) { os << ", "; } os << data[i]; first = false; } } os << "}"; return os; } // Convenience constructor for tests Uint64ArrayRW::Uint64ArrayRW(std::initializer_list<uint64_t> init) : Uint64Array(init.size()) { mData = new uint64_t[mSize]; memcpy(mData, init.begin(), mSize * sizeof(uint64_t)); } // Used in tests only. bool Uint64Array::operator==(const Uint64Array &other) const { if (size() != other.size()) { return false; } const uint64_t* thisData = data(); const uint64_t* thatData = other.data(); for (size_t i = 0; i < mSize; i++) { const uint64_t v1 = thisData != nullptr ? thisData[i] : 0; const uint64_t v2 = thatData != nullptr ? thatData[i] : 0; if (v1 != v2) { return false; } } return true; } template <> void LongArrayMultiStateCounter::add(std::vector<uint64_t>* value1, const std::vector<uint64_t>& value2, const uint64_t numerator, const uint64_t denominator) const { void LongArrayMultiStateCounter::add(Uint64ArrayRW *value1, const Uint64Array &value2, const uint64_t numerator, const uint64_t denominator) const { const uint64_t* data2 = value2.data(); if (data2 == nullptr) { return; } uint64_t* data1 = value1->dataRW(); size_t size = value2.size(); if (numerator != denominator) { for (int i = value2.size() - 1; i >= 0; i--) { for (size_t i = 0; i < size; i++) { // The caller ensures that denominator != 0 (*value1)[i] += value2[i] * numerator / denominator; data1[i] += data2[i] * numerator / denominator; } } else { for (int i = value2.size() - 1; i >= 0; i--) { (*value1)[i] += value2[i]; for (size_t i = 0; i < size; i++) { data1[i] += data2[i]; } } } template<> std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const { std::stringstream s; s << "{"; bool first = true; for (uint64_t n : v) { if (!first) { s << ", "; bool LongArrayMultiStateCounter::delta(const Uint64ArrayRW &previousValue, const Uint64Array &newValue, Uint64ArrayRW *outValue) const { size_t size = previousValue.size(); if (newValue.size() != size) { ALOGE("Incorrect array size: %d, should be %d", (int) newValue.size(), (int) size); return false; } if (outValue->size() != size) { ALOGE("Incorrect outValue size: %d, should be %d", (int) outValue->size(), (int) size); return false; } bool is_delta_valid = true; const uint64_t *prevData = previousValue.data(); const uint64_t *newData = newValue.data(); uint64_t *outData = outValue->dataRW(); for (size_t i = 0; i < size; i++) { if (prevData == nullptr) { if (newData == nullptr) { outData[i] = 0; } else { outData[i] = newData[i]; } } else if (newData == nullptr || newData[i] < prevData[i]) { outData[i] = 0; is_delta_valid = false; } else { outData[i] = newData[i] - prevData[i]; } s << n; first = false; } s << "}"; return s.str(); return is_delta_valid; } } // namespace battery Loading libs/battery/LongArrayMultiStateCounter.h +60 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,66 @@ namespace android { namespace battery { typedef MultiStateCounter<std::vector<uint64_t>> LongArrayMultiStateCounter; /** * Wrapper for an array of uint64's. */ class Uint64Array { protected: size_t mSize; public: Uint64Array() : Uint64Array(0) {} Uint64Array(size_t size) : mSize(size) {} virtual ~Uint64Array() {} size_t size() const { return mSize; } /** * Returns the wrapped array. * * Nullable! Null should be interpreted the same as an array of zeros */ virtual const uint64_t *data() const { return nullptr; } friend std::ostream &operator<<(std::ostream &os, const Uint64Array &v); // Test API bool operator==(const Uint64Array &other) const; }; /** * Mutable version of Uint64Array. */ class Uint64ArrayRW: public Uint64Array { uint64_t* mData; public: Uint64ArrayRW() : Uint64ArrayRW(0) {} Uint64ArrayRW(size_t size) : Uint64Array(size), mData(nullptr) {} Uint64ArrayRW(const Uint64Array ©); // Need an explicit copy constructor. In the initialization context C++ does not understand that // a Uint64ArrayRW is a Uint64Array. Uint64ArrayRW(const Uint64ArrayRW ©) : Uint64ArrayRW((const Uint64Array &) copy) {} // Test API Uint64ArrayRW(std::initializer_list<uint64_t> init); ~Uint64ArrayRW() override { delete[] mData; } const uint64_t *data() const override { return mData; } // NonNull. Will initialize the wrapped array if it is null. uint64_t *dataRW(); Uint64ArrayRW &operator=(const Uint64Array &t); }; typedef MultiStateCounter<Uint64ArrayRW, Uint64Array> LongArrayMultiStateCounter; } // namespace battery } // namespace android libs/battery/LongArrayMultiStateCounterTest.cpp +14 −14 Original line number Diff line number Diff line Loading @@ -24,25 +24,25 @@ namespace battery { class LongArrayMultiStateCounterTest : public testing::Test {}; TEST_F(LongArrayMultiStateCounterTest, stateChange) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); // Time was split in half between the two states, so the counts will be split 50:50 too EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(0)); EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(1)); EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(0)); EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(1)); } TEST_F(LongArrayMultiStateCounterTest, accumulation) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); testCounter.setState(0, 4000); testCounter.updateValue(std::vector<uint64_t>({200, 300, 400, 500}), 8000); testCounter.updateValue(Uint64ArrayRW({200, 300, 400, 500}), 8000); // The first delta is split 50:50: // 0: {50, 100, 150, 200} Loading @@ -50,16 +50,16 @@ TEST_F(LongArrayMultiStateCounterTest, accumulation) { // The second delta is split 4:1 // 0: {80, 80, 80, 80} // 1: {20, 20, 20, 20} EXPECT_EQ(std::vector<uint64_t>({130, 180, 230, 280}), testCounter.getCount(0)); EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1)); EXPECT_EQ(Uint64ArrayRW({130, 180, 230, 280}), testCounter.getCount(0)); EXPECT_EQ(Uint64ArrayRW({70, 120, 170, 220}), testCounter.getCount(1)); } TEST_F(LongArrayMultiStateCounterTest, toString) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1", testCounter.toString().c_str()); Loading libs/battery/MultiStateCounter.h +46 −45 Original line number Diff line number Diff line Loading @@ -35,12 +35,12 @@ namespace battery { typedef uint16_t state_t; template <class T> template <class T, class V> class MultiStateCounter { uint16_t stateCount; const uint16_t stateCount; const V emptyValue; state_t currentState; time_t lastStateChangeTimestamp; T emptyValue; T lastValue; time_t lastUpdateTimestamp; T deltaValue; Loading @@ -54,7 +54,7 @@ class MultiStateCounter { State* states; public: MultiStateCounter(uint16_t stateCount, const T& emptyValue); MultiStateCounter(uint16_t stateCount, const V& emptyValue); virtual ~MultiStateCounter(); Loading @@ -66,35 +66,35 @@ public: * Copies the current state and accumulated times-in-state from the source. Resets * the accumulated value. */ void copyStatesFrom(const MultiStateCounter<T>& source); void copyStatesFrom(const MultiStateCounter<T, V> &source); void setValue(state_t state, const T& value); void setValue(state_t state, const V& value); /** * Updates the value by distributing the delta from the previously set value * among states according to their respective time-in-state. * Returns the delta from the previously set value. */ const T& updateValue(const T& value, time_t timestamp); const V& updateValue(const V& value, time_t timestamp); /** * Updates the value by distributing the specified increment among states according * to their respective time-in-state. */ void incrementValue(const T& increment, time_t timestamp); void incrementValue(const V& increment, time_t timestamp); /** * Adds the specified increment to the value for the current state, without affecting * the last updated value or timestamp. Ignores partial time-in-state: the entirety of * the increment is given to the current state. */ void addValue(const T& increment); void addValue(const V& increment); void reset(); uint16_t getStateCount(); const T& getCount(state_t state); const V& getCount(state_t state); std::string toString(); Loading @@ -104,27 +104,25 @@ private: * Returns true iff the combination of previousValue and newValue is valid * (newValue >= prevValue) */ bool delta(const T& previousValue, const T& newValue, T* outValue) const; bool delta(const T& previousValue, const V& newValue, T* outValue) const; /** * Adds value2 to value1 and stores the result in value1. Denominator is * guaranteed to be non-zero. */ void add(T* value1, const T& value2, const uint64_t numerator, void add(T* value1, const V& value2, const uint64_t numerator, const uint64_t denominator) const; std::string valueToString(const T& value) const; }; // ---------------------- MultiStateCounter Implementation ------------------------- // Since MultiStateCounter is a template, the implementation must be inlined. template <class T> MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue) template <class T, class V> MultiStateCounter<T, V>::MultiStateCounter(uint16_t stateCount, const V& emptyValue) : stateCount(stateCount), emptyValue(emptyValue), currentState(0), lastStateChangeTimestamp(-1), emptyValue(emptyValue), lastValue(emptyValue), lastUpdateTimestamp(-1), deltaValue(emptyValue), Loading @@ -136,13 +134,13 @@ MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue } } template <class T> MultiStateCounter<T>::~MultiStateCounter() { template <class T, class V> MultiStateCounter<T, V>::~MultiStateCounter() { delete[] states; }; template <class T> void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::setEnabled(bool enabled, time_t timestamp) { if (enabled == isEnabled) { return; } Loading @@ -167,8 +165,8 @@ void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) { } } template <class T> void MultiStateCounter<T>::setState(state_t state, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::setState(state_t state, time_t timestamp) { if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) { // If the update arrived out-of-order, just push back the timestamp to // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate Loading Loading @@ -198,8 +196,8 @@ void MultiStateCounter<T>::setState(state_t state, time_t timestamp) { lastStateChangeTimestamp = timestamp; } template <class T> void MultiStateCounter<T>::copyStatesFrom(const MultiStateCounter<T>& source) { template <class T, class V> void MultiStateCounter<T, V>::copyStatesFrom(const MultiStateCounter<T, V>& source) { if (stateCount != source.stateCount) { ALOGE("State count mismatch: %u vs. %u\n", stateCount, source.stateCount); return; Loading @@ -214,14 +212,14 @@ void MultiStateCounter<T>::copyStatesFrom(const MultiStateCounter<T>& source) { lastUpdateTimestamp = source.lastUpdateTimestamp; } template <class T> void MultiStateCounter<T>::setValue(state_t state, const T& value) { template <class T, class V> void MultiStateCounter<T, V>::setValue(state_t state, const V& value) { states[state].counter = value; } template <class T> const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { T* returnValue = &emptyValue; template <class T, class V> const V& MultiStateCounter<T, V>::updateValue(const V& value, time_t timestamp) { const V* returnValue = &emptyValue; // If the counter is disabled, we ignore the update, except when the counter got disabled after // the previous update, in which case we still need to pick up the residual delta. Loading Loading @@ -250,8 +248,8 @@ const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { } } else { std::stringstream str; str << "updateValue is called with a value " << valueToString(value) << ", which is lower than the previous value " << valueToString(lastValue) str << "updateValue is called with a value " << value << ", which is lower than the previous value " << lastValue << "\n"; ALOGE("%s", str.str().c_str()); Loading @@ -276,23 +274,25 @@ const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { return *returnValue; } template <class T> void MultiStateCounter<T>::incrementValue(const T& increment, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::incrementValue(const V& increment, time_t timestamp) { // T newValue; // newValue = lastValue; // Copy assignment, not initialization. T newValue = lastValue; add(&newValue, increment, 1 /* numerator */, 1 /* denominator */); updateValue(newValue, timestamp); } template <class T> void MultiStateCounter<T>::addValue(const T& value) { template <class T, class V> void MultiStateCounter<T, V>::addValue(const V& value) { if (!isEnabled) { return; } add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */); } template <class T> void MultiStateCounter<T>::reset() { template <class T, class V> void MultiStateCounter<T, V>::reset() { lastStateChangeTimestamp = -1; lastUpdateTimestamp = -1; for (int i = 0; i < stateCount; i++) { Loading @@ -301,25 +301,26 @@ void MultiStateCounter<T>::reset() { } } template <class T> uint16_t MultiStateCounter<T>::getStateCount() { template <class T, class V> uint16_t MultiStateCounter<T, V>::getStateCount() { return stateCount; } template <class T> const T& MultiStateCounter<T>::getCount(state_t state) { template <class T, class V> const V& MultiStateCounter<T, V>::getCount(state_t state) { return states[state].counter; } template <class T> std::string MultiStateCounter<T>::toString() { template <class T, class V> std::string MultiStateCounter<T, V>::toString() { std::stringstream str; // str << "LAST VALUE: " << valueToString(lastValue); str << "["; for (int i = 0; i < stateCount; i++) { if (i != 0) { str << ", "; } str << i << ": " << valueToString(states[i].counter); str << i << ": " << states[i].counter; if (states[i].timeInStateSinceUpdate > 0) { str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate; } Loading libs/battery/MultiStateCounterTest.cpp +1 −6 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android { namespace battery { typedef MultiStateCounter<double> DoubleMultiStateCounter; typedef MultiStateCounter<double, double> DoubleMultiStateCounter; template <> bool DoubleMultiStateCounter::delta(const double& previousValue, const double& newValue, Loading @@ -41,11 +41,6 @@ void DoubleMultiStateCounter::add(double* value1, const double& value2, const ui } } template <> std::string DoubleMultiStateCounter::valueToString(const double& v) const { return std::to_string(v); } class MultiStateCounterTest : public testing::Test {}; TEST_F(MultiStateCounterTest, constructor) { Loading Loading
libs/battery/LongArrayMultiStateCounter.cpp +110 −34 Original line number Diff line number Diff line Loading @@ -21,58 +21,134 @@ namespace android { namespace battery { template <> bool LongArrayMultiStateCounter::delta(const std::vector<uint64_t>& previousValue, const std::vector<uint64_t>& newValue, std::vector<uint64_t>* outValue) const { size_t size = previousValue.size(); if (newValue.size() != size) { ALOGE("Incorrect array size: %d, should be %d", (int)newValue.size(), (int)size); return false; Uint64ArrayRW::Uint64ArrayRW(const Uint64Array ©) : Uint64Array(copy.size()) { if (mSize != 0 && copy.data() != nullptr) { mData = new uint64_t[mSize]; memcpy(mData, copy.data(), mSize * sizeof(uint64_t)); } else { mData = nullptr; } } bool is_delta_valid = true; for (int i = size - 1; i >= 0; i--) { if (newValue[i] >= previousValue[i]) { (*outValue)[i] = newValue[i] - previousValue[i]; uint64_t *Uint64ArrayRW::dataRW() { if (mData == nullptr) { mData = new uint64_t[mSize]; memset(mData, 0, mSize * sizeof(uint64_t)); } return mData; } Uint64ArrayRW &Uint64ArrayRW::operator=(const Uint64Array &t) { if (t.size() != mSize) { delete[] mData; mSize = t.size(); mData = nullptr; } if (mSize != 0) { if (t.data() != nullptr) { mData = new uint64_t[mSize]; memcpy(mData, t.data(), mSize * sizeof(uint64_t)); } else { (*outValue)[i] = 0; is_delta_valid = false; mData = nullptr; } } return is_delta_valid; return *this; } std::ostream &operator<<(std::ostream &os, const Uint64Array &v) { os << "{"; const uint64_t *data = v.data(); if (data != nullptr) { bool first = true; for (size_t i = 0; i < v.size(); i++) { if (!first) { os << ", "; } os << data[i]; first = false; } } os << "}"; return os; } // Convenience constructor for tests Uint64ArrayRW::Uint64ArrayRW(std::initializer_list<uint64_t> init) : Uint64Array(init.size()) { mData = new uint64_t[mSize]; memcpy(mData, init.begin(), mSize * sizeof(uint64_t)); } // Used in tests only. bool Uint64Array::operator==(const Uint64Array &other) const { if (size() != other.size()) { return false; } const uint64_t* thisData = data(); const uint64_t* thatData = other.data(); for (size_t i = 0; i < mSize; i++) { const uint64_t v1 = thisData != nullptr ? thisData[i] : 0; const uint64_t v2 = thatData != nullptr ? thatData[i] : 0; if (v1 != v2) { return false; } } return true; } template <> void LongArrayMultiStateCounter::add(std::vector<uint64_t>* value1, const std::vector<uint64_t>& value2, const uint64_t numerator, const uint64_t denominator) const { void LongArrayMultiStateCounter::add(Uint64ArrayRW *value1, const Uint64Array &value2, const uint64_t numerator, const uint64_t denominator) const { const uint64_t* data2 = value2.data(); if (data2 == nullptr) { return; } uint64_t* data1 = value1->dataRW(); size_t size = value2.size(); if (numerator != denominator) { for (int i = value2.size() - 1; i >= 0; i--) { for (size_t i = 0; i < size; i++) { // The caller ensures that denominator != 0 (*value1)[i] += value2[i] * numerator / denominator; data1[i] += data2[i] * numerator / denominator; } } else { for (int i = value2.size() - 1; i >= 0; i--) { (*value1)[i] += value2[i]; for (size_t i = 0; i < size; i++) { data1[i] += data2[i]; } } } template<> std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const { std::stringstream s; s << "{"; bool first = true; for (uint64_t n : v) { if (!first) { s << ", "; bool LongArrayMultiStateCounter::delta(const Uint64ArrayRW &previousValue, const Uint64Array &newValue, Uint64ArrayRW *outValue) const { size_t size = previousValue.size(); if (newValue.size() != size) { ALOGE("Incorrect array size: %d, should be %d", (int) newValue.size(), (int) size); return false; } if (outValue->size() != size) { ALOGE("Incorrect outValue size: %d, should be %d", (int) outValue->size(), (int) size); return false; } bool is_delta_valid = true; const uint64_t *prevData = previousValue.data(); const uint64_t *newData = newValue.data(); uint64_t *outData = outValue->dataRW(); for (size_t i = 0; i < size; i++) { if (prevData == nullptr) { if (newData == nullptr) { outData[i] = 0; } else { outData[i] = newData[i]; } } else if (newData == nullptr || newData[i] < prevData[i]) { outData[i] = 0; is_delta_valid = false; } else { outData[i] = newData[i] - prevData[i]; } s << n; first = false; } s << "}"; return s.str(); return is_delta_valid; } } // namespace battery Loading
libs/battery/LongArrayMultiStateCounter.h +60 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,66 @@ namespace android { namespace battery { typedef MultiStateCounter<std::vector<uint64_t>> LongArrayMultiStateCounter; /** * Wrapper for an array of uint64's. */ class Uint64Array { protected: size_t mSize; public: Uint64Array() : Uint64Array(0) {} Uint64Array(size_t size) : mSize(size) {} virtual ~Uint64Array() {} size_t size() const { return mSize; } /** * Returns the wrapped array. * * Nullable! Null should be interpreted the same as an array of zeros */ virtual const uint64_t *data() const { return nullptr; } friend std::ostream &operator<<(std::ostream &os, const Uint64Array &v); // Test API bool operator==(const Uint64Array &other) const; }; /** * Mutable version of Uint64Array. */ class Uint64ArrayRW: public Uint64Array { uint64_t* mData; public: Uint64ArrayRW() : Uint64ArrayRW(0) {} Uint64ArrayRW(size_t size) : Uint64Array(size), mData(nullptr) {} Uint64ArrayRW(const Uint64Array ©); // Need an explicit copy constructor. In the initialization context C++ does not understand that // a Uint64ArrayRW is a Uint64Array. Uint64ArrayRW(const Uint64ArrayRW ©) : Uint64ArrayRW((const Uint64Array &) copy) {} // Test API Uint64ArrayRW(std::initializer_list<uint64_t> init); ~Uint64ArrayRW() override { delete[] mData; } const uint64_t *data() const override { return mData; } // NonNull. Will initialize the wrapped array if it is null. uint64_t *dataRW(); Uint64ArrayRW &operator=(const Uint64Array &t); }; typedef MultiStateCounter<Uint64ArrayRW, Uint64Array> LongArrayMultiStateCounter; } // namespace battery } // namespace android
libs/battery/LongArrayMultiStateCounterTest.cpp +14 −14 Original line number Diff line number Diff line Loading @@ -24,25 +24,25 @@ namespace battery { class LongArrayMultiStateCounterTest : public testing::Test {}; TEST_F(LongArrayMultiStateCounterTest, stateChange) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); // Time was split in half between the two states, so the counts will be split 50:50 too EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(0)); EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(1)); EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(0)); EXPECT_EQ(Uint64ArrayRW({50, 100, 150, 200}), testCounter.getCount(1)); } TEST_F(LongArrayMultiStateCounterTest, accumulation) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); testCounter.setState(0, 4000); testCounter.updateValue(std::vector<uint64_t>({200, 300, 400, 500}), 8000); testCounter.updateValue(Uint64ArrayRW({200, 300, 400, 500}), 8000); // The first delta is split 50:50: // 0: {50, 100, 150, 200} Loading @@ -50,16 +50,16 @@ TEST_F(LongArrayMultiStateCounterTest, accumulation) { // The second delta is split 4:1 // 0: {80, 80, 80, 80} // 1: {20, 20, 20, 20} EXPECT_EQ(std::vector<uint64_t>({130, 180, 230, 280}), testCounter.getCount(0)); EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1)); EXPECT_EQ(Uint64ArrayRW({130, 180, 230, 280}), testCounter.getCount(0)); EXPECT_EQ(Uint64ArrayRW({70, 120, 170, 220}), testCounter.getCount(1)); } TEST_F(LongArrayMultiStateCounterTest, toString) { LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4)); testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000); LongArrayMultiStateCounter testCounter(2, Uint64Array(4)); testCounter.updateValue(Uint64ArrayRW({0, 0, 0, 0}), 1000); testCounter.setState(0, 1000); testCounter.setState(1, 2000); testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000); testCounter.updateValue(Uint64ArrayRW({100, 200, 300, 400}), 3000); EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1", testCounter.toString().c_str()); Loading
libs/battery/MultiStateCounter.h +46 −45 Original line number Diff line number Diff line Loading @@ -35,12 +35,12 @@ namespace battery { typedef uint16_t state_t; template <class T> template <class T, class V> class MultiStateCounter { uint16_t stateCount; const uint16_t stateCount; const V emptyValue; state_t currentState; time_t lastStateChangeTimestamp; T emptyValue; T lastValue; time_t lastUpdateTimestamp; T deltaValue; Loading @@ -54,7 +54,7 @@ class MultiStateCounter { State* states; public: MultiStateCounter(uint16_t stateCount, const T& emptyValue); MultiStateCounter(uint16_t stateCount, const V& emptyValue); virtual ~MultiStateCounter(); Loading @@ -66,35 +66,35 @@ public: * Copies the current state and accumulated times-in-state from the source. Resets * the accumulated value. */ void copyStatesFrom(const MultiStateCounter<T>& source); void copyStatesFrom(const MultiStateCounter<T, V> &source); void setValue(state_t state, const T& value); void setValue(state_t state, const V& value); /** * Updates the value by distributing the delta from the previously set value * among states according to their respective time-in-state. * Returns the delta from the previously set value. */ const T& updateValue(const T& value, time_t timestamp); const V& updateValue(const V& value, time_t timestamp); /** * Updates the value by distributing the specified increment among states according * to their respective time-in-state. */ void incrementValue(const T& increment, time_t timestamp); void incrementValue(const V& increment, time_t timestamp); /** * Adds the specified increment to the value for the current state, without affecting * the last updated value or timestamp. Ignores partial time-in-state: the entirety of * the increment is given to the current state. */ void addValue(const T& increment); void addValue(const V& increment); void reset(); uint16_t getStateCount(); const T& getCount(state_t state); const V& getCount(state_t state); std::string toString(); Loading @@ -104,27 +104,25 @@ private: * Returns true iff the combination of previousValue and newValue is valid * (newValue >= prevValue) */ bool delta(const T& previousValue, const T& newValue, T* outValue) const; bool delta(const T& previousValue, const V& newValue, T* outValue) const; /** * Adds value2 to value1 and stores the result in value1. Denominator is * guaranteed to be non-zero. */ void add(T* value1, const T& value2, const uint64_t numerator, void add(T* value1, const V& value2, const uint64_t numerator, const uint64_t denominator) const; std::string valueToString(const T& value) const; }; // ---------------------- MultiStateCounter Implementation ------------------------- // Since MultiStateCounter is a template, the implementation must be inlined. template <class T> MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue) template <class T, class V> MultiStateCounter<T, V>::MultiStateCounter(uint16_t stateCount, const V& emptyValue) : stateCount(stateCount), emptyValue(emptyValue), currentState(0), lastStateChangeTimestamp(-1), emptyValue(emptyValue), lastValue(emptyValue), lastUpdateTimestamp(-1), deltaValue(emptyValue), Loading @@ -136,13 +134,13 @@ MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue } } template <class T> MultiStateCounter<T>::~MultiStateCounter() { template <class T, class V> MultiStateCounter<T, V>::~MultiStateCounter() { delete[] states; }; template <class T> void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::setEnabled(bool enabled, time_t timestamp) { if (enabled == isEnabled) { return; } Loading @@ -167,8 +165,8 @@ void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) { } } template <class T> void MultiStateCounter<T>::setState(state_t state, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::setState(state_t state, time_t timestamp) { if (isEnabled && lastStateChangeTimestamp >= 0 && lastUpdateTimestamp >= 0) { // If the update arrived out-of-order, just push back the timestamp to // avoid having the situation where timeInStateSinceUpdate > timeSinceUpdate Loading Loading @@ -198,8 +196,8 @@ void MultiStateCounter<T>::setState(state_t state, time_t timestamp) { lastStateChangeTimestamp = timestamp; } template <class T> void MultiStateCounter<T>::copyStatesFrom(const MultiStateCounter<T>& source) { template <class T, class V> void MultiStateCounter<T, V>::copyStatesFrom(const MultiStateCounter<T, V>& source) { if (stateCount != source.stateCount) { ALOGE("State count mismatch: %u vs. %u\n", stateCount, source.stateCount); return; Loading @@ -214,14 +212,14 @@ void MultiStateCounter<T>::copyStatesFrom(const MultiStateCounter<T>& source) { lastUpdateTimestamp = source.lastUpdateTimestamp; } template <class T> void MultiStateCounter<T>::setValue(state_t state, const T& value) { template <class T, class V> void MultiStateCounter<T, V>::setValue(state_t state, const V& value) { states[state].counter = value; } template <class T> const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { T* returnValue = &emptyValue; template <class T, class V> const V& MultiStateCounter<T, V>::updateValue(const V& value, time_t timestamp) { const V* returnValue = &emptyValue; // If the counter is disabled, we ignore the update, except when the counter got disabled after // the previous update, in which case we still need to pick up the residual delta. Loading Loading @@ -250,8 +248,8 @@ const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { } } else { std::stringstream str; str << "updateValue is called with a value " << valueToString(value) << ", which is lower than the previous value " << valueToString(lastValue) str << "updateValue is called with a value " << value << ", which is lower than the previous value " << lastValue << "\n"; ALOGE("%s", str.str().c_str()); Loading @@ -276,23 +274,25 @@ const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) { return *returnValue; } template <class T> void MultiStateCounter<T>::incrementValue(const T& increment, time_t timestamp) { template <class T, class V> void MultiStateCounter<T, V>::incrementValue(const V& increment, time_t timestamp) { // T newValue; // newValue = lastValue; // Copy assignment, not initialization. T newValue = lastValue; add(&newValue, increment, 1 /* numerator */, 1 /* denominator */); updateValue(newValue, timestamp); } template <class T> void MultiStateCounter<T>::addValue(const T& value) { template <class T, class V> void MultiStateCounter<T, V>::addValue(const V& value) { if (!isEnabled) { return; } add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */); } template <class T> void MultiStateCounter<T>::reset() { template <class T, class V> void MultiStateCounter<T, V>::reset() { lastStateChangeTimestamp = -1; lastUpdateTimestamp = -1; for (int i = 0; i < stateCount; i++) { Loading @@ -301,25 +301,26 @@ void MultiStateCounter<T>::reset() { } } template <class T> uint16_t MultiStateCounter<T>::getStateCount() { template <class T, class V> uint16_t MultiStateCounter<T, V>::getStateCount() { return stateCount; } template <class T> const T& MultiStateCounter<T>::getCount(state_t state) { template <class T, class V> const V& MultiStateCounter<T, V>::getCount(state_t state) { return states[state].counter; } template <class T> std::string MultiStateCounter<T>::toString() { template <class T, class V> std::string MultiStateCounter<T, V>::toString() { std::stringstream str; // str << "LAST VALUE: " << valueToString(lastValue); str << "["; for (int i = 0; i < stateCount; i++) { if (i != 0) { str << ", "; } str << i << ": " << valueToString(states[i].counter); str << i << ": " << states[i].counter; if (states[i].timeInStateSinceUpdate > 0) { str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate; } Loading
libs/battery/MultiStateCounterTest.cpp +1 −6 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android { namespace battery { typedef MultiStateCounter<double> DoubleMultiStateCounter; typedef MultiStateCounter<double, double> DoubleMultiStateCounter; template <> bool DoubleMultiStateCounter::delta(const double& previousValue, const double& newValue, Loading @@ -41,11 +41,6 @@ void DoubleMultiStateCounter::add(double* value1, const double& value2, const ui } } template <> std::string DoubleMultiStateCounter::valueToString(const double& v) const { return std::to_string(v); } class MultiStateCounterTest : public testing::Test {}; TEST_F(MultiStateCounterTest, constructor) { Loading