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

Commit 41b10518 authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "Add FatVector"

parents 64d1f810 76ace115
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ LOCAL_SRC_FILES += \
    unit_tests/CanvasStateTests.cpp \
    unit_tests/ClipAreaTests.cpp \
    unit_tests/DamageAccumulatorTests.cpp \
    unit_tests/FatVectorTests.cpp \
    unit_tests/LinearAllocatorTests.cpp \
    unit_tests/StringUtilsTests.cpp

+98 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.
 */

#include <gtest/gtest.h>
#include <utils/FatVector.h>

#include <unit_tests/TestUtils.h>

using namespace android;
using namespace android::uirenderer;

template<class VectorType>
static bool allocationIsInternal(VectorType& v) {
    // allocation array (from &v[0] to &v[0] + v.capacity) is
    // located within the vector object itself
    return (char*)(&v) <= (char*)(&v[0])
            && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
}

TEST(FatVector, baseline) {
    // Verify allocation behavior FatVector contrasts against - allocations are always external
    std::vector<int> v;
    for (int i = 0; i < 50; i++) {
        v.push_back(i);
        EXPECT_FALSE(allocationIsInternal(v));
    }
}

TEST(FatVector, simpleAllocate) {
    FatVector<int, 4> v;
    EXPECT_EQ(4u, v.capacity());

    // can insert 4 items into internal buffer
    for (int i = 0; i < 4; i++) {
        v.push_back(i);
        EXPECT_TRUE(allocationIsInternal(v));
    }

    // then will fall back to external allocation
    for (int i = 5; i < 50; i++) {
        v.push_back(i);
        EXPECT_FALSE(allocationIsInternal(v));
    }
}

TEST(FatVector, shrink) {
    FatVector<int, 10> v;
    EXPECT_TRUE(allocationIsInternal(v));

    // push into external alloc
    v.resize(11);
    EXPECT_FALSE(allocationIsInternal(v));

    // shrinking back to internal alloc succeeds
    // note that shrinking further will succeed, but is a waste
    v.resize(10);
    v.shrink_to_fit();
    EXPECT_TRUE(allocationIsInternal(v));
}

TEST(FatVector, destructorInternal) {
    int count = 0;
    {
        // push 1 into external allocation, verify destruction happens once
        FatVector<TestUtils::SignalingDtor, 0> v;
        v.emplace_back(&count);
        EXPECT_FALSE(allocationIsInternal(v));
        EXPECT_EQ(0, count);
    }
    EXPECT_EQ(1, count);
}

TEST(FatVector, destructorExternal) {
    int count = 0;
    {
        // push 10 into internal allocation, verify 10 destructors called
        FatVector<TestUtils::SignalingDtor, 10> v;
        for (int i = 0; i < 10; i++) {
            v.emplace_back(&count);
            EXPECT_TRUE(allocationIsInternal(v));
        }
        EXPECT_EQ(0, count);
    }
    EXPECT_EQ(10, count);
}
+12 −32
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#include <gtest/gtest.h>
#include <utils/LinearAllocator.h>

#include <unit_tests/TestUtils.h>

using namespace android;
using namespace android::uirenderer;

@@ -25,27 +27,6 @@ struct SimplePair {
    int two = 2;
};

class SignalingDtor {
public:
    SignalingDtor() {
        mDestroyed = nullptr;
    }
    SignalingDtor(bool* destroyedSignal) {
        mDestroyed = destroyedSignal;
        *mDestroyed = false;
    }
    virtual ~SignalingDtor() {
        if (mDestroyed) {
            *mDestroyed = true;
        }
    }
    void setSignal(bool* destroyedSignal) {
        mDestroyed = destroyedSignal;
    }
private:
    bool* mDestroyed;
};

TEST(LinearAllocator, alloc) {
    LinearAllocator la;
    EXPECT_EQ(0u, la.usedSize());
@@ -62,31 +43,31 @@ TEST(LinearAllocator, alloc) {
}

TEST(LinearAllocator, dtor) {
    bool destroyed[10];
    int destroyed[10] = { 0 };
    {
        LinearAllocator la;
        for (int i = 0; i < 5; i++) {
            la.alloc<SignalingDtor>()->setSignal(destroyed + i);
            la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
            la.alloc<SimplePair>();
        }
        la.alloc(100);
        for (int i = 0; i < 5; i++) {
            auto sd = new (la) SignalingDtor(destroyed + 5 + i);
            auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
            la.autoDestroy(sd);
            new (la) SimplePair();
        }
        la.alloc(100);
        for (int i = 0; i < 10; i++) {
            EXPECT_FALSE(destroyed[i]);
            EXPECT_EQ(0, destroyed[i]);
        }
    }
    for (int i = 0; i < 10; i++) {
        EXPECT_TRUE(destroyed[i]);
        EXPECT_EQ(1, destroyed[i]);
    }
}

TEST(LinearAllocator, rewind) {
    bool destroyed;
    int destroyed = 0;
    {
        LinearAllocator la;
        auto addr = la.alloc(100);
@@ -94,17 +75,16 @@ TEST(LinearAllocator, rewind) {
        la.rewindIfLastAlloc(addr, 100);
        EXPECT_GT(16u, la.usedSize());
        size_t emptySize = la.usedSize();
        auto sigdtor = la.alloc<SignalingDtor>();
        auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
        sigdtor->setSignal(&destroyed);
        EXPECT_FALSE(destroyed);
        EXPECT_EQ(0, destroyed);
        EXPECT_LE(emptySize, la.usedSize());
        la.rewindIfLastAlloc(sigdtor);
        EXPECT_TRUE(destroyed);
        EXPECT_EQ(1, destroyed);
        EXPECT_EQ(emptySize, la.usedSize());
        destroyed = false;
    }
    // Checking for a double-destroy case
    EXPECT_EQ(destroyed, false);
    EXPECT_EQ(1, destroyed);
}

TEST(LinearStdAllocator, simpleAllocate) {
+18 −0
Original line number Diff line number Diff line
@@ -39,6 +39,24 @@ namespace uirenderer {

class TestUtils {
public:
    class SignalingDtor {
    public:
        SignalingDtor()
                : mSignal(nullptr) {}
        SignalingDtor(int* signal)
                : mSignal(signal) {}
        void setSignal(int* signal) {
            mSignal = signal;
        }
        ~SignalingDtor() {
            if (mSignal) {
                (*mSignal)++;
            }
        }
    private:
        int* mSignal;
    };

    static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
        for (int i = 0; i < 16; i++) {
            if (!MathUtils::areEqual(a[i], b[i])) {
+101 −0
Original line number Diff line number Diff line
/*
 * Copyright 2015, The Android Open Source Project
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ANDROID_FAT_VECTOR_H
#define ANDROID_FAT_VECTOR_H

#include "utils/Macros.h"

#include <stddef.h>
#include <type_traits>
#include <utils/Log.h>

#include <vector>

namespace android {
namespace uirenderer {

template <typename T, size_t SIZE>
class InlineStdAllocator {
public:
    struct Allocation {
        PREVENT_COPY_AND_ASSIGN(Allocation);
    public:
        Allocation() {};
        // char array instead of T array, so memory is uninitialized, with no destructors run
        char array[sizeof(T) * SIZE];
        bool inUse = false;
    };

    typedef T value_type; // needed to implement std::allocator
    typedef T* pointer; // needed to implement std::allocator

    InlineStdAllocator(Allocation& allocation)
            : mAllocation(allocation) {}
    InlineStdAllocator(const InlineStdAllocator& other)
            : mAllocation(other.mAllocation) {}
    ~InlineStdAllocator() {}

    T* allocate(size_t num, const void* = 0) {
        if (!mAllocation.inUse && num <= SIZE) {
            mAllocation.inUse = true;
            return (T*) mAllocation.array;
        } else {
            return (T*) malloc(num * sizeof(T));
        }
    }

    void deallocate(pointer p, size_t num) {
        if (p == (T*)mAllocation.array) {
            mAllocation.inUse = false;
        } else {
            // 'free' instead of delete here - destruction handled separately
            free(p);
        }
    }
    Allocation& mAllocation;
};

/**
 * std::vector with SIZE elements preallocated into an internal buffer.
 *
 * Useful for avoiding the cost of malloc in cases where only SIZE or
 * fewer elements are needed in the common case.
 */
template <typename T, size_t SIZE>
class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
public:
    FatVector() : std::vector<T, InlineStdAllocator<T, SIZE>>(
            InlineStdAllocator<T, SIZE>(mAllocation)) {
        this->reserve(SIZE);
    }
private:
    typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
};

}; // namespace uirenderer
}; // namespace android

#endif // ANDROID_FAT_VECTOR_H