diff options
author | Johannes Schickel | 2008-03-28 06:03:59 +0000 |
---|---|---|
committer | Johannes Schickel | 2008-03-28 06:03:59 +0000 |
commit | e29b4bb0cd4b4c71a3a53646b0eb728e7f156063 (patch) | |
tree | 5322a4a5791066416b84d72bc5c26a8dc01c8732 | |
parent | dc1a7004e949a5c1b8936f73387905e0f96f7e5c (diff) | |
download | scummvm-rg350-e29b4bb0cd4b4c71a3a53646b0eb728e7f156063.tar.gz scummvm-rg350-e29b4bb0cd4b4c71a3a53646b0eb728e7f156063.tar.bz2 scummvm-rg350-e29b4bb0cd4b4c71a3a53646b0eb728e7f156063.zip |
Committed shared pointer implementation of patch #1895703 "COMMON: Managed List".
Unlike the patch on the tracker this commit includes documentation for SharedPtr.
svn-id: r31287
-rw-r--r-- | common/ptr.h | 165 | ||||
-rw-r--r-- | engines/kyra/module.mk | 1 | ||||
-rw-r--r-- | engines/kyra/resource.cpp | 10 | ||||
-rw-r--r-- | engines/kyra/resource.h | 9 | ||||
-rw-r--r-- | test/common/ptr.h | 36 |
5 files changed, 212 insertions, 9 deletions
diff --git a/common/ptr.h b/common/ptr.h new file mode 100644 index 0000000000..809848aac1 --- /dev/null +++ b/common/ptr.h @@ -0,0 +1,165 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#ifndef COMMON_PTR_H +#define COMMON_PTR_H + +#include "common/scummsys.h" + +namespace Common { + +/** + * A simple shared pointer implementation modelled after boost. + * + * This object keeps track of the assigned pointer and automatically + * frees it when no more SharedPtr references to it exist. + * + * To achieve that the object implements an internal reference counting. + * Thus you should try to avoid using the plain pointer after assigning + * it to a SharedPtr object for the first time. If you still use the + * plain pointer be sure you do not delete it on your own. You may also + * not use the plain pointer to create a new SharedPtr object, since that + * would result in a double deletion of the pointer sooner or later. + * + * Example creation: + * Common::SharedPtr<int> pointer(new int(1)); + * would create a pointer to int. Later on usage via *pointer is the same + * as for a normal pointer. If you need to access the plain pointer value + * itself later on use the get method. The class also supplies a operator + * ->, which does the same as the -> operator on a normal pointer. + * + * Be sure you are using new to initialize the pointer you want to manage. + * Pointers pointing to memory not allocated by new, will cause undefined + * behavior on deletion. That is for example the case on pointers created + * with malloc (or similar) and new[]. This prevents the use of SharedPtr + * for arrays! + * + * Note that you have to specify the type itself not the pointer type as + * template parameter. You also need to have a real definition of the type + * you want to use, a simple forward definition is not enough. + * + * The class has implicit upcast support, so if you got a class B derived + * from class A, you can assign a pointer to B without any problems to a + * SharedPtr object with template parameter A. The very same applies to + * assigment of a SharedPtr<B> object to a SharedPtr<A> object. + * + * There are also operators != and == to compare two SharedPtr objects + * with compatible pointers. + */ +template<class T> +class SharedPtr { + template<class T2> friend class SharedPtr; +public: + typedef int RefValue; + typedef T ValueType; + typedef T *Pointer; + + SharedPtr() : _refCount(0), _pointer(0) {} + template<class T2> explicit SharedPtr(T2 *p) : _refCount(new RefValue(1)), _pointer(p) {} + + SharedPtr(const SharedPtr &r) : _refCount(r._refCount), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } + template<class T2> SharedPtr(const SharedPtr<T2> &r) : _refCount(r._refCount), _pointer(r._pointer) { if (_refCount) ++(*_refCount); } + + ~SharedPtr() { decRef(); } + + SharedPtr &operator =(const SharedPtr &r) { + if (r._refCount) + ++(*r._refCount); + decRef(); + + _refCount = r._refCount; + _pointer = r._pointer; + + return *this; + } + + template<class T2> + SharedPtr &operator =(const SharedPtr<T2> &r) { + if (r._refCount) + ++(*r._refCount); + decRef(); + + _refCount = r._refCount; + _pointer = r._pointer; + + return *this; + } + + ValueType &operator *() const { assert(_pointer); return *_pointer; } + Pointer operator ->() const { assert(_pointer); return _pointer; } + + /** + * Returns the plain pointer value. Be sure you know what you + * do if you are continuing to use that pointer. + * + * @return the pointer the SharedPtr object manages + */ + Pointer get() const { return _pointer; } + + operator bool() const { return _pointer != 0; } + + /** + * Checks if the SharedPtr object is the only object refering + * to the assigned pointer. This should just be used for + * debugging purposes. + */ + bool unique() const { return refCount() == 1; } + + /** + * Returns the number of references to the assigned pointer. + * This should just be used for debugging purposes. + */ + RefValue refCount() const { return _refCount ? *_refCount : 0; } +private: + void decRef() { + if (_refCount) { + --(*_refCount); + if (!*_refCount) { + delete _refCount; + delete _pointer; + _refCount = 0; + _pointer = 0; + } + } + } + + RefValue *_refCount; + T *_pointer; +}; + +} // end of namespace Common + +template<class T1, class T2> +bool operator ==(const Common::SharedPtr<T1> &l, const Common::SharedPtr<T2> &r) { + return l.get() == r.get(); +} + +template<class T1, class T2> +bool operator !=(const Common::SharedPtr<T1> &l, const Common::SharedPtr<T2> &r) { + return l.get() != r.get(); +} + + +#endif + diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 866cb61280..ce7b5ccd0a 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -5,6 +5,7 @@ MODULE_OBJS := \ animator_v2.o \ debugger.o \ detection.o \ + gui.o \ gui_v1.o \ gui_v2.o \ items_v1.o \ diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp index 0f7da48495..3cf8336e7f 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -29,7 +29,6 @@ #include "common/file.h" #include "common/fs.h" #include "common/func.h" -#include "common/algorithm.h" #include "gui/message.h" @@ -43,8 +42,6 @@ Resource::Resource(KyraEngine *vm) : _loaders(), _map(), _vm(vm) { Resource::~Resource() { unloadAllPakFiles(); - for (LoaderIterator i = _loaders.begin(); i != _loaders.end(); ++i) - delete (*i); _loaders.clear(); } @@ -666,17 +663,18 @@ Common::SeekableReadStream *ResLoaderIns::loadFileFromArchive(const Common::Stri } void Resource::initializeLoaders() { - _loaders.push_back(new ResLoaderPak()); - _loaders.push_back(new ResLoaderIns()); + _loaders.push_back(LoaderList::value_type(new ResLoaderPak())); + _loaders.push_back(LoaderList::value_type(new ResLoaderIns())); } const ResArchiveLoader *Resource::getLoader(ResFileEntry::kType type) const { for (CLoaderIterator i = _loaders.begin(); i != _loaders.end(); ++i) { if ((*i)->getType() == type) - return *i; + return (*i).get(); } return 0; } } // end of namespace Kyra + diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index ace8c413f4..2c0d7b9c79 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -34,6 +34,7 @@ #include "common/hash-str.h" #include "common/hashmap.h" #include "common/stream.h" +#include "common/ptr.h" #include "kyra/kyra.h" @@ -113,9 +114,10 @@ protected: void initializeLoaders(); const ResArchiveLoader *getLoader(ResFileEntry::kType type) const; - typedef Common::List<ResArchiveLoader*>::iterator LoaderIterator; - typedef Common::List<ResArchiveLoader*>::const_iterator CLoaderIterator; - Common::List<ResArchiveLoader*> _loaders; + typedef Common::List<Common::SharedPtr<ResArchiveLoader> > LoaderList; + typedef LoaderList::iterator LoaderIterator; + typedef LoaderList::const_iterator CLoaderIterator; + LoaderList _loaders; ResFileMap _map; KyraEngine *_vm; @@ -334,3 +336,4 @@ private: #endif + diff --git a/test/common/ptr.h b/test/common/ptr.h new file mode 100644 index 0000000000..b6f2e950ca --- /dev/null +++ b/test/common/ptr.h @@ -0,0 +1,36 @@ +#include <cxxtest/TestSuite.h> + +#include "common/ptr.h" + +class PtrTestSuite : public CxxTest::TestSuite +{ + public: + void test_assign() { + Common::SharedPtr<int> p1(new int(1)); + TS_ASSERT(p1.unique()); + TS_ASSERT_EQUALS(*p1, 1); + + { + Common::SharedPtr<int> p2 = p1; + TS_ASSERT(!p1.unique()); + TS_ASSERT(p1.refCount() == p2.refCount()); + TS_ASSERT(p1.refCount() == 2); + TS_ASSERT(p1 == p2); + TS_ASSERT_EQUALS(*p2, 1); + { + Common::SharedPtr<int> p3; + p3 = p2; + TS_ASSERT(p3 == p2 && p3 == p1); + TS_ASSERT(p1.refCount() == 3); + TS_ASSERT_EQUALS(*p3, 1); + *p3 = 0; + TS_ASSERT_EQUALS(*p3, 0); + } + TS_ASSERT_EQUALS(*p2, 0); + TS_ASSERT(p1.refCount() == 2); + } + + TS_ASSERT_EQUALS(*p1, 0); + TS_ASSERT(p1.unique()); + } +}; |