diff options
Diffstat (limited to 'emulator/opengl/shared/emugl/common')
-rw-r--r-- | emulator/opengl/shared/emugl/common/Android.mk | 34 | ||||
-rw-r--r-- | emulator/opengl/shared/emugl/common/smart_ptr.cpp | 111 | ||||
-rw-r--r-- | emulator/opengl/shared/emugl/common/smart_ptr.h | 150 | ||||
-rw-r--r-- | emulator/opengl/shared/emugl/common/smart_ptr_unittest.cpp | 140 |
4 files changed, 435 insertions, 0 deletions
diff --git a/emulator/opengl/shared/emugl/common/Android.mk b/emulator/opengl/shared/emugl/common/Android.mk new file mode 100644 index 0000000..0af670c --- /dev/null +++ b/emulator/opengl/shared/emugl/common/Android.mk @@ -0,0 +1,34 @@ +# This build script corresponds to a library containing many definitions +# common to both the guest and the host. They relate to +# +LOCAL_PATH := $(call my-dir) + +### emugl_common host library ########################################### + +commonSources := \ + smart_ptr.cpp \ + +host_commonSources := $(commonSources) + +$(call emugl-begin-host-static-library,libemugl_common) +LOCAL_SRC_FILES := $(host_commonSources) +$(call emugl-end-module) + +$(call emugl-begin-host-static-library,lib64emugl_common) +LOCAL_SRC_FILES := $(host_commonSources) +$(call emugl-export,CFLAGS,-m64) +$(call emugl-end-module) + + +### emugl_common_unittests ############################################## + +host_commonSources := \ + smart_ptr_unittest.cpp + +$(call emugl-begin-host-executable,emugl_common_host_unittests) +LOCAL_SRC_FILES := $(host_commonSources) +LOCAL_C_INCLUDES += external/gtest/include +$(call emugl-export,STATIC_LIBRARIES, libemugl_common libgtest_host libgtest_main_host) +$(call emugl-end-module) + +# TODO(digit): 64-bit version, once we have 64-bit gtest. diff --git a/emulator/opengl/shared/emugl/common/smart_ptr.cpp b/emulator/opengl/shared/emugl/common/smart_ptr.cpp new file mode 100644 index 0000000..9ac7339 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/smart_ptr.cpp @@ -0,0 +1,111 @@ +// Copyright (C) 2014 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 "emugl/common/smart_ptr.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +namespace emugl { + +// Thread-safe atomic reference-counting type. +class RefCount { +public: + RefCount() : mCount(1) {} + ~RefCount() {} + + // Technically not thread-safe, use only for testing. + int count() const { return (int)mCount; } + + void increment() { +#ifdef _WIN32 + InterlockedIncrement(&mCount); +#else + __sync_fetch_and_add(&mCount, 1); +#endif + } + + bool decrement() { +#ifdef _WIN32 + return InterlockedDecrement(&mCount) == 0; +#else + return __sync_add_and_fetch(&mCount, -1) == 0; +#endif + } + +private: +#ifdef _WIN32 + LONG mCount; +#else + int mCount; +#endif +}; + + +// SmartPtrBase implementation. + +SmartPtrBase::SmartPtrBase(void* ptr) : mPtr(ptr), mRefCount(NULL) { + if (mPtr) + mRefCount = new RefCount(); +} + + +SmartPtrBase::SmartPtrBase(const SmartPtrBase& other) + : mPtr(other.mPtr), mRefCount(other.mRefCount) { + if (mRefCount) + mRefCount->increment(); +} + + +int SmartPtrBase::getRefCount() const { + return mRefCount ? mRefCount->count() : 0; +} + + +void SmartPtrBase::addRef() { + if (mRefCount) + mRefCount->increment(); +} + + +void* SmartPtrBase::copyFrom(const SmartPtrBase& other) { + void* old_ptr = release(); + + mPtr = other.mPtr; + mRefCount = other.mRefCount; + if (mRefCount) + mRefCount->increment(); + + return old_ptr; +} + + +void* SmartPtrBase::release() { + void* old_ptr = mPtr; + RefCount* old_refcount = mRefCount; + + if (old_refcount) { + mPtr = NULL; + mRefCount = NULL; + + if (old_refcount->decrement()) + return old_ptr; + } + + return NULL; +} + +} // namespace emugl diff --git a/emulator/opengl/shared/emugl/common/smart_ptr.h b/emulator/opengl/shared/emugl/common/smart_ptr.h new file mode 100644 index 0000000..2d7db5b --- /dev/null +++ b/emulator/opengl/shared/emugl/common/smart_ptr.h @@ -0,0 +1,150 @@ +// Copyright (C) 2014 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. +#ifndef EMUGL_SMART_PTR_H +#define EMUGL_SMART_PTR_H + +#include <stddef.h> + +namespace emugl { + +// Hidden atomic ref-counting implementation. +class RefCount; + +// Base class for all templated SmartPtr<> instances. Reduces +// template expansion and code. Consider this to be an implementation +// detail of SmartPtr<>, so don't rely on anything here. +class SmartPtrBase { +public: + // Defrault constructor. + SmartPtrBase() : mPtr(NULL), mRefCount(NULL) {} + + // Normal constructor. This takes ownership of |ptr|, though only + // template instances are capable of destroying the object. + explicit SmartPtrBase(void* ptr); + + // Copy-constructor, this increments the reference count. + SmartPtrBase(const SmartPtrBase& other); + + // Assignment operator, also increments the reference count. + SmartPtrBase& operator=(const SmartPtrBase& other); + + // Nothing happens in this constructor, the real work must be performed + // in subclasses. + ~SmartPtrBase() {} + + + // Used to enable 'if (smart_ptr) { ... }' properly. + operator void*() const { + return mPtr; + } + + // Return internal reference count value, only use for unit testing. + int getRefCount() const; + +protected: + // Used internally to increment the reference count. + void addRef(); + + // Copy the |other| into this instance, returns the old pointer value + // if it needs to be destroyed by the caller, or NULL otherwise. + void* copyFrom(const SmartPtrBase& other); + + // Used internally to decrement the reference count, if it reaches 0, + // returns the pointer to be destroyed, NULL otherwise. + void* release(); + + void* mPtr; + RefCount* mRefCount; +}; + + +// The real template class to be used for smart pointers. +// Typical uses: +// +// SmartPtr<Foo> ptr(new Foo()); // takes ownership. +// SmartPtr<Foo> ptr2; // empty pointer. +// ptr2 = ptr; // copies pointer + increment reference count. +// Foo* obj = ptr.Ptr(); // access pointed object. +// ptr->DoStuff(); // operate directly on pointed object. +// (*ptr)->DoStuff(); // same here. +// +// On scope exit, the internal reference count is decremented and the +// object is deleted automatically when it reaches 0, indicating that +// there are no more owners. +// +// IMPORTANT: You need to be sure that only one 'chain' of smart pointers +// own a given object. I.e. the following is incorrect: +// +// Foo* foo = new Foo(); // create new instance. +// SmartPtr<Foo> ptr(foo); // |ptr| takes ownership of |foo|. +// SmartPtr<Foo> ptr2(foo); // |ptr2| takes also ownership of |foo|. +// +// The problem is that |ptr| and |ptr2| don't know anything about each +// other, and will not share the same reference count. Once a smart pointer +// owns an object, only use other smart pointers that are copy-constructed +// or assigned with the initial one to keep everything consistent. +template <class T> +class SmartPtr : public emugl::SmartPtrBase { +public: + // Default constructor. The instance holds a NULL pointer. + SmartPtr() : SmartPtrBase() {} + + // Regular constructor, takes ownership of |ptr|. + explicit SmartPtr(T* ptr) : SmartPtrBase(ptr) {} + + // Copy-constructor, |this| and |other| will share the same internal + // reference count, which is incremented by 1. + SmartPtr(const SmartPtr& other) + : SmartPtrBase(reinterpret_cast<const SmartPtrBase&>(other)) {} + + // Assignment operator, same semantics as copy-constructor. + SmartPtr& operator=(const SmartPtr& other) { + void* old_ptr = copyFrom(static_cast<const SmartPtrBase&>(other)); + if (old_ptr) + delete reinterpret_cast<T*>(old_ptr); + return *this; + } + + // Destructor, decrements reference count and destroys the object + // if it reaches 0 (indicating this was the last owning smart pointer). + ~SmartPtr() { + void* ptr = release(); + if (ptr) + delete reinterpret_cast<T*>(ptr); + } + + // Return owned object instance, or NULL. + T* Ptr() const { + return reinterpret_cast<T*>(mPtr); + } + + // Return owned object instance, or NULL + const T* constPtr() const { + return reinterpret_cast<const T*>(mPtr); + } + + // Operate directly on owned object. + T* operator->() const { + return Ptr(); + } + + // Return reference to owned object. + T& operator*() const { + return *Ptr(); + } +}; + +} // namespace emugl + +#endif // EMUGL_SMART_PTR_H diff --git a/emulator/opengl/shared/emugl/common/smart_ptr_unittest.cpp b/emulator/opengl/shared/emugl/common/smart_ptr_unittest.cpp new file mode 100644 index 0000000..db9e5f2 --- /dev/null +++ b/emulator/opengl/shared/emugl/common/smart_ptr_unittest.cpp @@ -0,0 +1,140 @@ +// Copyright (C) 2014 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 "emugl/common/smart_ptr.h" + +#include <gtest/gtest.h> + +namespace emugl { + +// This Test sub-class is used to track allocations and deallocations of +// the MyTestClass instances that are created through newInstance(). +// See below for typical usage. +class SmartPtrTest : public testing::Test { +public: + SmartPtrTest() : mNewCount(0), mDeleteCount(0), mDoCount(0) {} + + ~SmartPtrTest() { + mNewCount = 0; + mDoCount = 0; + mDeleteCount = 0; + } + + class MyClass; + + MyClass* newInstance() { + return new MyClass(this); + } + + class MyClass { + public: + MyClass(SmartPtrTest* test) : mTest(test) { + mTest->mNewCount++; + } + + void doStuff() { + mTest->mDoCount++; + } + + ~MyClass() { + mTest->mDeleteCount++; + } + private: + SmartPtrTest* mTest; + }; + + int mNewCount; + int mDeleteCount; + int mDoCount; +}; + + +TEST_F(SmartPtrTest, Empty) { + SmartPtr<MyClass> ptr; + EXPECT_FALSE(ptr.Ptr()); + + EXPECT_EQ(0, mNewCount); + EXPECT_EQ(0, mDeleteCount); + EXPECT_EQ(0, mDoCount); +} + + +TEST_F(SmartPtrTest, SingleRef) { + MyClass* obj = newInstance(); + EXPECT_EQ(1, mNewCount); + + { + SmartPtr<MyClass> ptr(obj); + EXPECT_EQ(obj, ptr.Ptr()); + + EXPECT_EQ(1, mNewCount); + EXPECT_EQ(0, mDeleteCount); + EXPECT_EQ(0, mDoCount); + } + // Check that the object was deleted. + EXPECT_EQ(1, mDeleteCount); +} + + +TEST_F(SmartPtrTest, CopyConstructor) { + MyClass* obj = newInstance(); + EXPECT_EQ(1, mNewCount); + + { + SmartPtr<MyClass> ptr1(obj); + { + SmartPtr<MyClass> ptr2(ptr1); + EXPECT_EQ(2, ptr1.getRefCount()); + EXPECT_EQ(2, ptr2.getRefCount()); + EXPECT_EQ(1, mNewCount); + EXPECT_EQ(0, mDeleteCount); + EXPECT_EQ(0, mDoCount); + } + EXPECT_EQ(1, mNewCount); + EXPECT_EQ(0, mDeleteCount); + EXPECT_EQ(0, mDoCount); + } + EXPECT_EQ(1, mNewCount); + EXPECT_EQ(1, mDeleteCount); + EXPECT_EQ(0, mDoCount); +} + + +TEST_F(SmartPtrTest, AssignmentOperator) { + SmartPtr<MyClass> ptr1(newInstance()); + SmartPtr<MyClass> ptr2(newInstance()); + EXPECT_EQ(2, mNewCount); + EXPECT_EQ(0, mDeleteCount); + EXPECT_EQ(0, mDoCount); + + ptr2 = ptr1; + EXPECT_EQ(2, mNewCount); + EXPECT_EQ(1, mDeleteCount); + + EXPECT_EQ(ptr1.Ptr(), ptr2.Ptr()); + EXPECT_EQ(2, ptr1.getRefCount()); + EXPECT_EQ(2, ptr2.getRefCount()); +} + + +TEST_F(SmartPtrTest, ArrowOperator) { + SmartPtr<MyClass> ptr(newInstance()); + ptr->doStuff(); + EXPECT_EQ(1, mDoCount); + + (*ptr).doStuff(); + EXPECT_EQ(2, mDoCount); +} + +} // namespace emugl |