diff --git a/dart/common/smart_ptr.h b/dart/common/smart_ptr.h new file mode 100644 index 0000000000000..960250fe381e9 --- /dev/null +++ b/dart/common/smart_ptr.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2015, Georgia Tech Research Corporation + * All rights reserved. + * + * Author(s): Jeongseok Lee + * + * Georgia Tech Graphics Lab and Humanoid Robotics Lab + * + * Directed by Prof. C. Karen Liu and Prof. Mike Stilman + * + * + * This file is provided under the following "BSD-style" License: + * 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 AND + * CONTRIBUTORS "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 HOLDER 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 DART_COMMON_SMARTPOINTER_H_ +#define DART_COMMON_SMARTPOINTER_H_ + +#include +#include + +namespace dart { +namespace common { + +namespace smart_ptr { +namespace detail { + +template +struct data_body +{ + data_body(T* _ptr) : observer_count(0), data(_ptr) {} + ~data_body() {} + bool valid() const { return nullptr != data; } + size_t observer_count; + T* data; +}; + +} // namespace detail +} // namespace smart_ptr + +template +class observer_pointer; + +/// subject_ptr is very similar to std::unique_ptr. +/// subject_ptr is resposible to delete data +template +class subject_pointer +{ +public: + + friend class observer_pointer; + + /// Default constructor + constexpr subject_pointer() : mDataBody(nullptr) {} + + /// Constructor with null pointer + constexpr subject_pointer(std::nullptr_t) : mDataBody(nullptr) {} + + /// Constructor with given data pointer + subject_pointer(T* _ptr) + : mDataBody(new smart_ptr::detail::data_body(_ptr)) {} + + /// Non-copyable + subject_pointer(const subject_pointer&) = delete; + + /// Move constructor + subject_pointer(subject_pointer&& _other) + : mDataBody(std::move(_other.mDataBody)) + { + _other.mDataBody = nullptr; + } + + /// + ~subject_pointer() + { + if (mDataBody) + { + delete mDataBody->data; + mDataBody->data = nullptr; + + if (0 == mDataBody->observer_count) + delete mDataBody; + } + } + + /// Non-assignable + subject_pointer& operator=(const subject_pointer&) = delete; + + /// Move assignment + subject_pointer& operator=(subject_pointer&& _other) + { + if (this == &_other) + return *this; + + mDataBody = std::move(_other.mDataBody); + _other.mDataBody = nullptr; + return *this; + } + + /// Implicit conversion to pointer type + operator T*() const { return mDataBody->data; } + + /// Dereferencing operator + T& operator*() const { return *mDataBody->data; } + + /// Dereferencing operation + T* operator->() { return mDataBody->data; } + + /// Get the subscription of this subject_pointer + T* get() const { return mDataBody->data; } + + /// Replaces the managed object + void reset(subject_pointer _ptr = subject_pointer()) + { + + } + + /// Get true if the data is still not deleted + bool valid() + { + if (mDataBody) + return mDataBody->valid(); + else + return false; + } + + /// Get number of observerse + size_t getNumObservers() const { return mDataBody->observer_count; } + +protected: + /// The actual data will be stored here. + smart_ptr::detail::data_body* mDataBody; +}; + +template +class observer_pointer +{ +public: + /// Default constructor + constexpr observer_pointer() : mDataBody(nullptr) {} + + /// Constructor with null pointer + constexpr observer_pointer(std::nullptr_t) : mDataBody(nullptr) {} + + /// Constructor given observer_pointer + observer_pointer(const observer_pointer& _obPtr) + : mDataBody(_obPtr.mDataBody) + { + if (mDataBody) + mDataBody->observer_count++; + } + + /// Move constructor given observer_pointer + observer_pointer(observer_pointer&& _obPtr) + : mDataBody(std::move(_obPtr.mDataBody)) + { + _obPtr.mDataBody = nullptr; + } + + /// Constructor given subject_pointer + observer_pointer(const subject_pointer& _subPtr) + : mDataBody(_subPtr.mDataBody) + { + if (mDataBody) + mDataBody->observer_count++; + } + + /// Destructor + ~observer_pointer() + { + releaseDataBody(); + } + + /// Assign onther observer_pointer + observer_pointer& operator=(const observer_pointer& _other) + { + if (this == &_other) + return *this; + + // If observing the same data, then do nothing + if (mDataBody == _other.mDataBody) + return *this; + + releaseDataBody(); + + mDataBody = _other.mDataBody; + + if (mDataBody) + mDataBody->observer_count++; + + return *this; + } + + /// Move onther observer_pointer + observer_pointer& operator=(observer_pointer&& _other) + { + if (this == &_other) + return *this; + + mDataBody = std::move(_other.mDataBody); + _other.mDataBody = nullptr; + return *this; + } + + /// Assign subject_pointer + observer_pointer& operator=(const subject_pointer& _other) + { + releaseDataBody(); + + mDataBody = _other.mDataBody; + + if (mDataBody) + mDataBody->observer_count++; + + return *this; + } + + /// Implicit conversion to pointer type + operator T*() const { return mDataBody->data; } + + /// Dereferencing operator + T& operator*() const { return *mDataBody->data; } + + /// Dereferencing operation + T* operator->() { return mDataBody->data; } + + /// Get the subscription of this observer_pointer + T* get() const { return mDataBody->data; } + + /// True if and only if this observer_pointer still points to a valid data + bool valid() + { + if (mDataBody) + return mDataBody->valid(); + else + return false; + } + +private: + /// + void releaseDataBody() + { + if (mDataBody) + { + mDataBody->observer_count--; + if (0 == mDataBody->observer_count && !mDataBody->valid()) + delete mDataBody; + } + } + + /// Data body + smart_ptr::detail::data_body* mDataBody; +}; + +template +using sub_ptr = subject_pointer; + +template +using ob_ptr = observer_pointer; + +} // namespace common +} // namespace dart + +#endif // DART_COMMON_SMARTPOINTER_H_ + diff --git a/unittests/testSmartPointer.cpp b/unittests/testSmartPointer.cpp new file mode 100644 index 0000000000000..77893f4627760 --- /dev/null +++ b/unittests/testSmartPointer.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, Georgia Tech Research Corporation + * All rights reserved. + * + * Author(s): Jeongseok Lee + * + * Georgia Tech Graphics Lab and Humanoid Robotics Lab + * + * Directed by Prof. C. Karen Liu and Prof. Mike Stilman + * + * + * This file is provided under the following "BSD-style" License: + * 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 AND + * CONTRIBUTORS "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 HOLDER 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. + */ + +#include + +#include "dart/common/smart_ptr.h" +#include "dart/dynamics/SimpleFrame.h" +#include "dart/dynamics/BoxShape.h" + +using namespace dart; +using namespace common; +using namespace dynamics; + +//============================================================================== +class BodyNode +{ +public: + BodyNode() : mName("bodyNodeName") + { std::cout << "BodyNode created." << std::endl; } + ~BodyNode() { std::cout << "BodyNode destroyed." << std::endl; } + const std::string& getName() const { return mName; } +protected: + std::string mName; +}; + +class Skeleton +{ +public: + Skeleton() : mBodyNode(new BodyNode()) + { std::cout << "Skeleton created." << std::endl; } + ~Skeleton() { std::cout << "Skeleton destroyed." << std::endl; } + + ob_ptr getBodyNode() { return mBodyNode; } + const std::string& getBodyNodeName() { return mBodyNode->getName(); } + +protected: + sub_ptr mBodyNode; +}; + +//============================================================================== +TEST(SmartPointer, SkeletonBodyNodeUseCase) +{ + ob_ptr opBodyNode; + EXPECT_FALSE(opBodyNode.valid()); + + Skeleton* skel = new Skeleton(); + + opBodyNode = skel->getBodyNode(); + EXPECT_TRUE(opBodyNode.valid()); + EXPECT_EQ(opBodyNode->getName(), skel->getBodyNodeName()); + + delete skel; + EXPECT_FALSE(opBodyNode.valid()); +} + +//============================================================================== +TEST(SmartPointer, Validation) +{ + ob_ptr obDetachable; + ob_ptr obSimpleFrame; + + { + sub_ptr spDetachable + = new Detachable(Frame::World(), "entity", false); + sub_ptr spSimpleFrame + = new SimpleFrame(Frame::World(), "frame"); + + EXPECT_TRUE(spDetachable.valid()); + EXPECT_TRUE(spSimpleFrame.valid()); + + obDetachable = spDetachable; + obSimpleFrame = spSimpleFrame; + + EXPECT_TRUE(obDetachable.valid()); + EXPECT_TRUE(obSimpleFrame.valid()); + } + + EXPECT_FALSE(obDetachable.valid()); + EXPECT_FALSE(obSimpleFrame.valid()); +} + +//============================================================================== +Entity* getPointer(Entity* _ptr) +{ + return _ptr; +} + +//============================================================================== +TEST(SmartPointer, ImplicitConversion) +{ + sub_ptr entity_ptr = new Entity(Frame::World(), "entity", false); + + // This checks whether the sub_ptr class can successfully be implicitly + // converted to the type of class it's supposed to be pointing to + EXPECT_TRUE(getPointer(entity_ptr) == entity_ptr.get()); +} + +//============================================================================== +int main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}