aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/opengl/shared/emugl/common
diff options
context:
space:
mode:
Diffstat (limited to 'emulator/opengl/shared/emugl/common')
-rw-r--r--emulator/opengl/shared/emugl/common/Android.mk34
-rw-r--r--emulator/opengl/shared/emugl/common/smart_ptr.cpp111
-rw-r--r--emulator/opengl/shared/emugl/common/smart_ptr.h150
-rw-r--r--emulator/opengl/shared/emugl/common/smart_ptr_unittest.cpp140
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