diff options
| -rw-r--r-- | CMakeLists.txt | 161 | ||||
| -rw-r--r-- | src/core/managed/Managed.cpp | 27 | ||||
| -rw-r--r-- | src/core/managed/Managed.hpp (renamed from src/core/Managed.hpp) | 243 | ||||
| -rw-r--r-- | src/core/managed/ManagedContainer.cpp | 24 | ||||
| -rw-r--r-- | src/core/managed/ManagedContainer.hpp (renamed from src/core/ManagedContainers.hpp) | 13 | ||||
| -rw-r--r-- | src/core/managed/Manager.cpp (renamed from src/core/Managed.cpp) | 67 | ||||
| -rw-r--r-- | src/core/managed/Manager.hpp | 250 | ||||
| -rw-r--r-- | test/core/managed/ManagedContainerTest.cpp (renamed from test/core/ManagedContainersTest.cpp) | 4 | ||||
| -rw-r--r-- | test/core/managed/ManagedTest.cpp | 22 | ||||
| -rw-r--r-- | test/core/managed/ManagerTest.cpp (renamed from test/core/ManagedTest.cpp) | 139 | ||||
| -rw-r--r-- | test/core/managed/TestManaged.hpp (renamed from test/core/TestManaged.hpp) | 2 | 
11 files changed, 526 insertions, 426 deletions
| diff --git a/CMakeLists.txt b/CMakeLists.txt index cac6061..841d828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,55 +99,57 @@ ADD_DEFINITIONS(  )  ADD_LIBRARY(ousia_core -	src/core/CodeTokenizer -	src/core/CSS -	src/core/Managed -	src/core/Node -	src/core/Registry -	src/core/ResourceLocator -	src/core/Tokenizer -	src/core/common/CharReader -	src/core/common/Exceptions -	src/core/common/Logger -	src/core/common/Utils -	src/core/common/Variant -	src/core/common/VariantReader +#	src/core/CodeTokenizer +#	src/core/CSS +#	src/core/Node +#	src/core/Registry +#	src/core/ResourceLocator +#	src/core/Tokenizer +#	src/core/common/CharReader +#	src/core/common/Exceptions +#	src/core/common/Logger +#	src/core/common/Utils +#	src/core/common/Variant +#	src/core/common/VariantReader +	src/core/managed/Managed +	src/core/managed/Manager +	src/core/managed/ManagedContainer  #	src/core/model/Domain -	src/core/model/Typesystem -	src/core/parser/Parser -	src/core/parser/ParserStack -	src/core/parser/Scope +#	src/core/model/Typesystem +#	src/core/parser/Parser +#	src/core/parser/ParserStack +#	src/core/parser/Scope  #	src/core/script/Function  #	src/core/script/Object  #	src/core/script/ScriptEngine  #	src/core/script/Variant  ) -ADD_LIBRARY(ousia_boost -	src/plugins/boost/FileLocator -) +#ADD_LIBRARY(ousia_boost +#	src/plugins/boost/FileLocator +#) -TARGET_LINK_LIBRARIES(ousia_boost -	ousia_core -	${Boost_LIBRARIES} -) +#TARGET_LINK_LIBRARIES(ousia_boost +#	ousia_core +#	${Boost_LIBRARIES} +#) -ADD_LIBRARY(ousia_css -	src/plugins/css/CSSParser -) +#ADD_LIBRARY(ousia_css +#	src/plugins/css/CSSParser +#) -TARGET_LINK_LIBRARIES(ousia_css -	ousia_core -) +#TARGET_LINK_LIBRARIES(ousia_css +#	ousia_core +#) -ADD_LIBRARY(ousia_xml -	src/plugins/xml/XmlParser -) +#ADD_LIBRARY(ousia_xml +#	src/plugins/xml/XmlParser +#) -TARGET_LINK_LIBRARIES(ousia_xml -	ousia_core -	${EXPAT_LIBRARIES} -) +#TARGET_LINK_LIBRARIES(ousia_xml +#	ousia_core +#	${EXPAT_LIBRARIES} +#)  #ADD_LIBRARY(ousia_mozjs  #	src/plugins/mozjs/MozJsScriptEngine @@ -166,21 +168,22 @@ IF(TEST)  	)  	ADD_EXECUTABLE(ousia_test_core -		test/core/CodeTokenizerTest -		test/core/CSSTest -		test/core/ManagedTest -		test/core/ManagedContainersTest -		test/core/NodeTest -		test/core/RangeSetTest -		test/core/RegistryTest -		test/core/ResourceLocatorTest -		test/core/TokenizerTest -		test/core/common/CharReaderTest -		test/core/common/LoggerTest -		test/core/common/VariantReaderTest -		test/core/common/VariantTest -		test/core/common/UtilsTest -		test/core/parser/ParserStackTest +#		test/core/CodeTokenizerTest +#		test/core/CSSTest +#		test/core/NodeTest +#		test/core/RangeSetTest +#		test/core/RegistryTest +#		test/core/ResourceLocatorTest +#		test/core/TokenizerTest +#		test/core/common/CharReaderTest +#		test/core/common/LoggerTest +#		test/core/common/VariantReaderTest +#		test/core/common/VariantTest +#		test/core/common/UtilsTest +		test/core/managed/ManagedTest +		test/core/managed/ManagerTest +		test/core/managed/ManagedContainerTest +#		test/core/parser/ParserStackTest  #		test/core/script/FunctionTest  #		test/core/script/ObjectTest  #		test/core/script/VariantTest @@ -191,35 +194,35 @@ IF(TEST)  		ousia_core  	) -	ADD_EXECUTABLE(ousia_test_boost -		test/plugins/boost/FileLocatorTest -	) +#	ADD_EXECUTABLE(ousia_test_boost +#		test/plugins/boost/FileLocatorTest +#	) -	TARGET_LINK_LIBRARIES(ousia_test_boost -		${GTEST_LIBRARIES} -		ousia_core -		ousia_boost -	) +#	TARGET_LINK_LIBRARIES(ousia_test_boost +#		${GTEST_LIBRARIES} +#		ousia_core +#		ousia_boost +#	) -	ADD_EXECUTABLE(ousia_test_css -		test/plugins/css/CSSParserTest -	) +#	ADD_EXECUTABLE(ousia_test_css +#		test/plugins/css/CSSParserTest +#	) -	TARGET_LINK_LIBRARIES(ousia_test_css -		${GTEST_LIBRARIES} -		ousia_core -		ousia_css -	) +#	TARGET_LINK_LIBRARIES(ousia_test_css +#		${GTEST_LIBRARIES} +#		ousia_core +#		ousia_css +#	) -	ADD_EXECUTABLE(ousia_test_xml -		test/plugins/xml/XmlParserTest -	) +#	ADD_EXECUTABLE(ousia_test_xml +#		test/plugins/xml/XmlParserTest +#	) -	TARGET_LINK_LIBRARIES(ousia_test_xml -		${GTEST_LIBRARIES} -		ousia_core -		ousia_xml -	) +#	TARGET_LINK_LIBRARIES(ousia_test_xml +#		${GTEST_LIBRARIES} +#		ousia_core +#		ousia_xml +#	)  #	ADD_EXECUTABLE(ousia_test_mozjs  #		test/plugins/mozjs/MozJsScriptEngineTest @@ -233,9 +236,9 @@ IF(TEST)  	# Register the unit tests  	ADD_TEST(ousia_test_core ousia_test_core) -	ADD_TEST(ousia_test_boost ousia_test_boost) -	ADD_TEST(ousia_test_xml ousia_test_xml) -	ADD_TEST(ousia_test_css ousia_test_css) +#	ADD_TEST(ousia_test_boost ousia_test_boost) +#	ADD_TEST(ousia_test_xml ousia_test_xml) +#	ADD_TEST(ousia_test_css ousia_test_css)  #	ADD_TEST(ousia_test_mozjs ousia_test_mozjs)  ENDIF() diff --git a/src/core/managed/Managed.cpp b/src/core/managed/Managed.cpp new file mode 100644 index 0000000..991f941 --- /dev/null +++ b/src/core/managed/Managed.cpp @@ -0,0 +1,27 @@ +/* +    Ousía +    Copyright (C) 2014, 2015  Benjamin Paaßen, Andreas Stöckel + +    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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include <cassert> +#include <queue> + +#include "Managed.hpp" + +namespace ousia { + + +} diff --git a/src/core/Managed.hpp b/src/core/managed/Managed.hpp index 25fa14b..04c2f84 100644 --- a/src/core/Managed.hpp +++ b/src/core/managed/Managed.hpp @@ -19,19 +19,10 @@  #ifndef _OUSIA_MANAGED_HPP_  #define _OUSIA_MANAGED_HPP_ -#include <iostream> -#include <map> -#include <type_traits> -#include <unordered_map> -#include <unordered_set> -#include <vector> +#include "Manager.hpp"  namespace ousia { -// TODO: Implement clone, getReferenced and getReferencing - -class Managed; -  template <class T>  class Handle; @@ -41,237 +32,7 @@ class Rooted;  template <class T>  class Owned; -/** - * Enum used to specify the direction of a object reference (inbound or - * outbound). - */ -enum class RefDir { IN, OUT }; - -/** - * The ObjectDescriptor struct is used by the Manager for reference counting and - * garbage collection. It describes the reference multigraph with adjacency - * lists. Each ObjectDescriptor instance represents a single managed object and - * its assocition to and from other managed objects (nodes in the graph). - */ -struct ObjectDescriptor { -public: -	/** -	 * Contains the number of references to rooted handles. A managed objects -	 * whith at least one rooted reference is considered reachable. -	 */ -	int rootRefCount; - -	/** -	 * Map containing all references pointing at this managed object. The -	 * map key describes the object which points at this object, the map -	 * value contains the reference count from this object. -	 */ -	std::map<Managed *, int> refIn; - -	/** -	 * Map containing all references pointing from this managed object to -	 * other managed objects. The map key describes the target object and -	 * the map value the reference count. -	 */ -	std::map<Managed *, int> refOut; - -	/** -	 * Default constructor of the ObjectDescriptor class. -	 */ -	ObjectDescriptor() : rootRefCount(0){}; - -	/** -	 * Returns the total input degree of this managed object. The root -	 * references are also counted as incomming references and thus added to -	 * the result. -	 * -	 * @return the input degree of this node, including the root references. -	 */ -	int refInCount() const; - -	/** -	 * Returns the total output degree of this node. -	 * -	 * @return the output degree of this node. -	 */ -	int refOutCount() const; - -	/** -	 * Returns the input degree for the given managed object. -	 * -	 * @param o is the node for which the input degree should be returned, -	 * nullptr if the number of root references is returned. -	 * @return the input degree of the node or the rootRefCount if nullptr -	 * is given as node. If the node is not found, zero is returned. -	 */ -	int refInCount(Managed *o) const; - -	/** -	 * Returns the output degree for the given node. -	 * -	 * @param o is the node for which the output degree should be returned. -	 * @return the output degree of the node. If the node is not found, zero -	 * is returned. -	 */ -	int refOutCount(Managed *o) const; - -	/** -	 * Increments the input or output degree for the represented managed -	 * object. -	 * -	 * @param dir describes the direction of the association. A value of -	 * "in", increments the input degree, otherwise increments the output -	 * degree. -	 * @param o is the managed object for which the input or output degree -	 * should be incremented. If the given object is null, the rootRefCount -	 * is incremented, independent of the dir parameter. -	 */ -	void incrDegree(RefDir dir, Managed *o); - -	/** -	 * Decrements the input or output degree for the given managed object. -	 * -	 * @param dir describes the direction of the association. A value of -	 * "in", increments the input degree, otherwise increments the output -	 * degree. -	 * @param o is the managed object for which the input or output degree -	 * should be incremented. If the given object is null, the rootRefCount -	 * is incremented, independent of the dir parameter. -	 * @param all specifies whether the degree of the reference to this -	 * object should be set to zero, no matter what the actual degree is. -	 * This parameter is used when the given object is deleted and all -	 * references to it should be purged, no matter what. -	 * @return true if the degree was sucessfully decremented. -	 */ -	bool decrDegree(RefDir dir, Managed *o, bool all = false); -}; - -class Manager { -private: -	/** -	 * Default sweep threshold. If the number of managed objects marked for -	 * sweeping reaches this threshold a garbage collection sweep is performed. -	 */ -	static constexpr size_t SWEEP_THRESHOLD = 128; - -protected: -	/** -	 * Threshold that defines the minimum number of entries in the "marked" -	 * set until "sweep" is called. -	 */ -	const size_t threshold; - -	/** -	 * Map used to store the descriptors for all managed objects. Every object -	 * that has at least one root, in or out reference has an entry in this map. -	 */ -	std::unordered_map<Managed *, ObjectDescriptor> objects; - -	/** -	 * Set containing the objects marked for sweeping. -	 */ -	std::unordered_set<Managed *> marked; - -	/** -	 * Set containing objects marked for deletion. -	 */ -	std::unordered_set<Managed *> deleted; - -	/** -	 * Recursion depth while performing deletion. This variable is needed -	 * because the deletion of an object may cause further objects to be -	 * deleted. Yet the actual deletion should only be performed at the -	 * uppermost recursion level. -	 */ -	int deletionRecursionDepth = 0; - -	/** -	 * Returns the object ObjectDescriptor for the given object from the objects -	 * map. -	 */ -	ObjectDescriptor *getDescriptor(Managed *o); - -	/** -	 * Purges the objects in the "deleted" set. -	 */ -	void purgeDeleted(); - -	/** -	 * Function used internally to delete a object and clean up all references -	 * in the object manager still pointing at it. -	 * -	 * @param o is the object that should be deleted. -	 * @param descr is a reference to the ObjectDescriptor of the given object. -	 */ -	void deleteObject(Managed *o, ObjectDescriptor *descr); - -	/** -	 * Internal version of the deleteRef function with an additional "all" -	 * parameter. Removes a reference to the given target object from the source -	 * object. -	 * -	 * @param tar is the target object for which the reference from the given -	 * source object should be removed. -	 * @param src is the source object from which the target object was -	 * referenced or nullptr if the target object is referenced from the local -	 * scope. -	 * @param all specifies whether all (src, tar) references should be deleted, -	 * independent of the actual cardinality. This is set to true, when the -	 * given object is deleted and all references to it should be purged, no -	 * matter what. -	 */ -	void deleteRef(Managed *tar, Managed *src, bool all); - -public: -	Manager() : threshold(SWEEP_THRESHOLD) {} - -	Manager(size_t threshold) : threshold(threshold) {} - -	/** -	 * Deletes all objects managed by this class. -	 */ -	~Manager(); - -	/** -	 * Registers an object for being managed by the Manager. The Manager now has -	 * the sole responsibility for freeing the managed object. Under no -	 * circumstances free the object manually, this will result in double frees. -	 * -	 * @param o is the object which is registered for being used with the -	 * Manager. -	 */ -	void manage(Managed *o); - -	/** -	 * Stores a reference to the given target object from the given source -	 * object. If the source pointer is set to nullptr, this means that the -	 * target object is rooted (semantic: it is reachable from the current -	 * scope) and should not be collected. -	 * -	 * @param tar is the target object to which the reference from src should be -	 * stored. -	 * @param src is the source object from which the target object is -	 * referenced or nullptr if the target object is referenced from the local -	 * scope. -	 */ -	void addRef(Managed *tar, Managed *src); - -	/** -	 * Removes a reference to the given target object from the source object. -	 * -	 * @param tar is the target object for which the reference from the given -	 * source object should be removed. -	 * @param src is the source object from which the target object was -	 * referenced or nullptr if the target object is referenced from the local -	 * scope. -	 */ -	void deleteRef(Managed *tar, Managed *src) { deleteRef(tar, src, false); } - -	/** -	 * Performs garbage collection. -	 */ -	void sweep(); -}; +// TODO: Implement clone, getReferenced and getReferencing  /**   * The Managed class represents a garbage collected object. Instances of the diff --git a/src/core/managed/ManagedContainer.cpp b/src/core/managed/ManagedContainer.cpp new file mode 100644 index 0000000..e7f30fa --- /dev/null +++ b/src/core/managed/ManagedContainer.cpp @@ -0,0 +1,24 @@ +/* +    Ousía +    Copyright (C) 2014, 2015  Benjamin Paaßen, Andreas Stöckel + +    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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "ManagedContainer.hpp" + +namespace ousia { + +} + diff --git a/src/core/ManagedContainers.hpp b/src/core/managed/ManagedContainer.hpp index 9447fff..9ff75d5 100644 --- a/src/core/ManagedContainers.hpp +++ b/src/core/managed/ManagedContainer.hpp @@ -16,8 +16,15 @@      along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ -#ifndef _OUSIA_MANAGED_CONTAINERS_H_ -#define _OUSIA_MANAGED_CONTAINERS_H_ +#ifndef _OUSIA_MANAGED_CONTAINER_H_ +#define _OUSIA_MANAGED_CONTAINER_H_ + +#include <unordered_map> +#include <unordered_set> +#include <vector> +#include <iostream> +#include <map> +#include <type_traits>  #include "Managed.hpp" @@ -380,5 +387,5 @@ public:  };  } -#endif /* _OUSIA_MANAGED_CONTAINERS_H_ */ +#endif /* _OUSIA_MANAGED_CONTAINER_H_ */ diff --git a/src/core/Managed.cpp b/src/core/managed/Manager.cpp index f3a68a3..7b562a8 100644 --- a/src/core/Managed.cpp +++ b/src/core/managed/Manager.cpp @@ -16,10 +16,8 @@      along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ -#include <cassert> -#include <queue> -  #include "Managed.hpp" +#include "Manager.hpp"  namespace ousia { @@ -52,47 +50,12 @@ public:  /* Class ObjectDescriptor */ -int ObjectDescriptor::refInCount() const -{ -	int res = 0; -	for (const auto &e : refIn) { -		res += e.second; -	} -	return res + rootRefCount; -} - -int ObjectDescriptor::refOutCount() const -{ -	int res = 0; -	for (const auto &e : refOut) { -		res += e.second; -	} -	return res; -} - -int ObjectDescriptor::refInCount(Managed *o) const +bool Manager::ObjectDescriptor::hasInRef() const  { -	if (o == nullptr) { -		return rootRefCount; -	} - -	const auto it = refIn.find(o); -	if (it != refIn.cend()) { -		return it->second; -	} -	return 0; +	return rootRefCount > 0 || !refIn.empty();  } -int ObjectDescriptor::refOutCount(Managed *o) const -{ -	const auto it = refOut.find(o); -	if (it != refOut.cend()) { -		return it->second; -	} -	return 0; -} - -void ObjectDescriptor::incrDegree(RefDir dir, Managed *o) +void Manager::ObjectDescriptor::incrDegree(RefDir dir, Managed *o)  {  	// If the given Managed is null it refers to an input rooted reference  	if (o == nullptr) { @@ -112,7 +75,7 @@ void ObjectDescriptor::incrDegree(RefDir dir, Managed *o)  	}  } -bool ObjectDescriptor::decrDegree(RefDir dir, Managed *o, bool all) +bool Manager::ObjectDescriptor::decrDegree(RefDir dir, Managed *o, bool all)  {  	// If the given Managed is null it refers to an input rooted reference  	if (o == nullptr) { @@ -153,7 +116,8 @@ Manager::~Manager()  	// All objects should have been deleted!  	assert(objects.empty()); -	// Free all objects managed by the Managed manager (we'll get here if assertions +	// Free all objects managed by the Managed manager (we'll get here if +	// assertions  	// are disabled)  	if (!objects.empty()) {  		ScopedIncrement incr{deletionRecursionDepth}; @@ -163,7 +127,7 @@ Manager::~Manager()  	}  } -ObjectDescriptor *Manager::getDescriptor(Managed *o) +Manager::ObjectDescriptor *Manager::getDescriptor(Managed *o)  {  	if (o) {  		auto it = objects.find(o); @@ -212,13 +176,15 @@ void Manager::deleteRef(Managed *tar, Managed *src, bool all)  	// Decrement the input degree of the input Managed  	if (dTar && dTar->decrDegree(RefDir::IN, src, all)) { -		// If the Managed has a zero in degree, it can be safely deleted, otherwise +		// If the Managed has a zero in degree, it can be safely deleted, +		// otherwise  		// if it has no root reference, add it to the "marked" set which is  		// subject to tracing garbage collection -		if (dTar->refInCount() == 0) { +		if (!dTar->hasInRef()) {  			deleteObject(tar, dTar);  		} else if (dTar->rootRefCount == 0) { -			// Insert the Managed into the list of objects to be inspected by garbage +			// Insert the Managed into the list of objects to be inspected by +			// garbage  			// collection  			marked.insert(tar);  		} @@ -292,7 +258,8 @@ void Manager::sweep()  	// Set containing objects which are reachable from a rooted Managed  	std::unordered_set<Managed *> reachable; -	// Deletion of objects may cause other objects to be added to the "marked" list +	// Deletion of objects may cause other objects to be added to the "marked" +	// list  	// so we repeat this process until objects are no longer deleted  	while (!marked.empty()) {  		// Repeat until all objects in the "marked" list have been visited @@ -333,7 +300,8 @@ void Manager::sweep()  					Managed *srcManaged = src.first;  					// Abort if the Managed already in the reachable list, -					// otherwise add the Managed to the queue if it was not visited +					// otherwise add the Managed to the queue if it was not +					// visited  					if (reachable.find(srcManaged) != reachable.end()) {  						isReachable = true;  						break; @@ -362,3 +330,4 @@ void Manager::sweep()  	}  }  } + diff --git a/src/core/managed/Manager.hpp b/src/core/managed/Manager.hpp new file mode 100644 index 0000000..95d08e1 --- /dev/null +++ b/src/core/managed/Manager.hpp @@ -0,0 +1,250 @@ +/* +    Ousía +    Copyright (C) 2014, 2015  Benjamin Paaßen, Andreas Stöckel + +    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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +/** + * @file Manager.hpp + * + * Definition of the Manager class used for garbage collection. + * + * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) + */ + +#ifndef _OUSIA_MANAGER_HPP_ +#define _OUSIA_MANAGER_HPP_ + +#include <cassert> +#include <map> +#include <unordered_map> +#include <unordered_set> +#include <vector> +#include <queue> + +namespace ousia { + +// Forward declaration +class Managed; + +class Manager { +public: +	/** +	 * Enum used to specify the direction of a object reference (inbound or +	 * outbound). +	 */ +	enum class RefDir { IN, OUT }; + +	/** +	 * The ObjectDescriptor struct is used by the Manager for reference counting +	 * and garbage collection. It describes the reference multigraph with +	 * adjacency lists. Each ObjectDescriptor instance represents a single +	 * managed object and its assocition to and from other managed objects +	 * (nodes in the graph). +	 */ +	struct ObjectDescriptor { +	public: +		/** +		 * Contains the number of references to rooted handles. A managed +		 * objects +		 * whith at least one rooted reference is considered reachable. +		 */ +		int rootRefCount; + +		/** +		 * Map containing all references pointing at this managed object. The +		 * map key describes the object which points at this object, the map +		 * value contains the reference count from this object. +		 */ +		std::map<Managed *, int> refIn; + +		/** +		 * Map containing all references pointing from this managed object to +		 * other managed objects. The map key describes the target object and +		 * the map value the reference count. +		 */ +		std::map<Managed *, int> refOut; + +		/** +		 * Default constructor of the ObjectDescriptor class. +		 */ +		ObjectDescriptor() : rootRefCount(0){}; + +		/** +		 * Returns true, if the ObjectDescriptor has at least one input +		 * reference. +		 */ +		bool hasInRef() const; + +		/** +		 * Increments the input or output degree for the represented managed +		 * object. +		 * +		 * @param dir describes the direction of the association. A value of +		 * "in", increments the input degree, otherwise increments the output +		 * degree. +		 * @param o is the managed object for which the input or output degree +		 * should be incremented. If the given object is null, the rootRefCount +		 * is incremented, independent of the dir parameter. +		 */ +		void incrDegree(RefDir dir, Managed *o); + +		/** +		 * Decrements the input or output degree for the given managed object. +		 * +		 * @param dir describes the direction of the association. A value of +		 * "in", increments the input degree, otherwise increments the output +		 * degree. +		 * @param o is the managed object for which the input or output degree +		 * should be incremented. If the given object is null, the rootRefCount +		 * is incremented, independent of the dir parameter. +		 * @param all specifies whether the degree of the reference to this +		 * object should be set to zero, no matter what the actual degree is. +		 * This parameter is used when the given object is deleted and all +		 * references to it should be purged, no matter what. +		 * @return true if the degree was sucessfully decremented. +		 */ +		bool decrDegree(RefDir dir, Managed *o, bool all = false); +	}; + +private: +	/** +	 * Default sweep threshold. If the number of managed objects marked for +	 * sweeping reaches this threshold a garbage collection sweep is performed. +	 */ +	static constexpr size_t SWEEP_THRESHOLD = 128; + +protected: +	/** +	 * Threshold that defines the minimum number of entries in the "marked" +	 * set until "sweep" is called. +	 */ +	const size_t threshold; + +	/** +	 * Map used to store the descriptors for all managed objects. Every object +	 * that has at least one root, in or out reference has an entry in this map. +	 */ +	std::unordered_map<Managed *, ObjectDescriptor> objects; + +	/** +	 * Set containing the objects marked for sweeping. +	 */ +	std::unordered_set<Managed *> marked; + +	/** +	 * Set containing objects marked for deletion. +	 */ +	std::unordered_set<Managed *> deleted; + +	/** +	 * Recursion depth while performing deletion. This variable is needed +	 * because the deletion of an object may cause further objects to be +	 * deleted. Yet the actual deletion should only be performed at the +	 * uppermost recursion level. +	 */ +	int deletionRecursionDepth = 0; + +	/** +	 * Returns the object ObjectDescriptor for the given object from the objects +	 * map. +	 */ +	ObjectDescriptor *getDescriptor(Managed *o); + +	/** +	 * Purges the objects in the "deleted" set. +	 */ +	void purgeDeleted(); + +	/** +	 * Function used internally to delete a object and clean up all references +	 * in the object manager still pointing at it. +	 * +	 * @param o is the object that should be deleted. +	 * @param descr is a reference to the ObjectDescriptor of the given object. +	 */ +	void deleteObject(Managed *o, ObjectDescriptor *descr); + +	/** +	 * Internal version of the deleteRef function with an additional "all" +	 * parameter. Removes a reference to the given target object from the source +	 * object. +	 * +	 * @param tar is the target object for which the reference from the given +	 * source object should be removed. +	 * @param src is the source object from which the target object was +	 * referenced or nullptr if the target object is referenced from the local +	 * scope. +	 * @param all specifies whether all (src, tar) references should be deleted, +	 * independent of the actual cardinality. This is set to true, when the +	 * given object is deleted and all references to it should be purged, no +	 * matter what. +	 */ +	void deleteRef(Managed *tar, Managed *src, bool all); + +public: +	Manager() : threshold(SWEEP_THRESHOLD) {} + +	Manager(size_t threshold) : threshold(threshold) {} + +	/** +	 * Deletes all objects managed by this class. +	 */ +	~Manager(); + +	/** +	 * Registers an object for being managed by the Manager. The Manager now has +	 * the sole responsibility for freeing the managed object. Under no +	 * circumstances free the object manually, this will result in double frees. +	 * +	 * @param o is the object which is registered for being used with the +	 * Manager. +	 */ +	void manage(Managed *o); + +	/** +	 * Stores a reference to the given target object from the given source +	 * object. If the source pointer is set to nullptr, this means that the +	 * target object is rooted (semantic: it is reachable from the current +	 * scope) and should not be collected. +	 * +	 * @param tar is the target object to which the reference from src should be +	 * stored. +	 * @param src is the source object from which the target object is +	 * referenced or nullptr if the target object is referenced from the local +	 * scope. +	 */ +	void addRef(Managed *tar, Managed *src); + +	/** +	 * Removes a reference to the given target object from the source object. +	 * +	 * @param tar is the target object for which the reference from the given +	 * source object should be removed. +	 * @param src is the source object from which the target object was +	 * referenced or nullptr if the target object is referenced from the local +	 * scope. +	 */ +	void deleteRef(Managed *tar, Managed *src) { deleteRef(tar, src, false); } + +	/** +	 * Performs garbage collection. +	 */ +	void sweep(); +}; +} + +#endif /* _OUSIA_MANAGER_HPP_ */ + diff --git a/test/core/ManagedContainersTest.cpp b/test/core/managed/ManagedContainerTest.cpp index 3abbd4d..db72295 100644 --- a/test/core/ManagedContainersTest.cpp +++ b/test/core/managed/ManagedContainerTest.cpp @@ -20,8 +20,8 @@  #include <gtest/gtest.h> -#include <core/Managed.hpp> -#include <core/ManagedContainers.hpp> +#include <core/managed/Managed.hpp> +#include <core/managed/ManagedContainer.hpp>  #include "TestManaged.hpp" diff --git a/test/core/managed/ManagedTest.cpp b/test/core/managed/ManagedTest.cpp new file mode 100644 index 0000000..e8a24f2 --- /dev/null +++ b/test/core/managed/ManagedTest.cpp @@ -0,0 +1,22 @@ +/* +    Ousía +    Copyright (C) 2014, 2015  Benjamin Paaßen, Andreas Stöckel + +    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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +namespace ousia { + +} + diff --git a/test/core/ManagedTest.cpp b/test/core/managed/ManagerTest.cpp index ab60f04..da42f0a 100644 --- a/test/core/ManagedTest.cpp +++ b/test/core/managed/ManagerTest.cpp @@ -22,7 +22,7 @@  #include <gtest/gtest.h> -#include <core/Managed.hpp> +#include <core/managed/Managed.hpp>  #include "TestManaged.hpp" @@ -30,128 +30,171 @@ namespace ousia {  /* Class ObjectDescriptor */ +class TestObjectDescriptor : public Manager::ObjectDescriptor { +public: +	int refInCount() const +	{ +		int res = 0; +		for (const auto &e : refIn) { +			res += e.second; +		} +		return res + rootRefCount; +	} + +	int refOutCount() const +	{ +		int res = 0; +		for (const auto &e : refOut) { +			res += e.second; +		} +		return res; +	} + +	int refInCount(Managed *o) const +	{ +		if (o == nullptr) { +			return rootRefCount; +		} + +		const auto it = refIn.find(o); +		if (it != refIn.cend()) { +			return it->second; +		} +		return 0; +	} + +	int refOutCount(Managed *o) const +	{ +		const auto it = refOut.find(o); +		if (it != refOut.cend()) { +			return it->second; +		} +		return 0; +	} +}; +  TEST(ObjectDescriptor, degree)  {  	// Do not use actual Managed in this test -- we don't want to test their  	// behaviour -	ObjectDescriptor nd; +	TestObjectDescriptor nd;  	Managed *n1 = reinterpret_cast<Managed *>(intptr_t{0x10});  	Managed *n2 = reinterpret_cast<Managed *>(intptr_t{0x20});  	// Input degree -	ASSERT_EQ(0, nd.refIn.size()); +	ASSERT_EQ(0U, nd.refIn.size());  	ASSERT_EQ(0, nd.refInCount(n1)); -	nd.incrDegree(RefDir::IN, n1); +	nd.incrDegree(Manager::RefDir::IN, n1);  	ASSERT_EQ(1, nd.refInCount());  	ASSERT_EQ(1, nd.refInCount(n1));  	ASSERT_EQ(0, nd.refInCount(n2)); -	ASSERT_EQ(1, nd.refIn.size()); +	ASSERT_EQ(1U, nd.refIn.size()); -	nd.incrDegree(RefDir::IN, n1); +	nd.incrDegree(Manager::RefDir::IN, n1);  	ASSERT_EQ(2, nd.refInCount());  	ASSERT_EQ(2, nd.refInCount(n1));  	ASSERT_EQ(0, nd.refInCount(n2)); -	ASSERT_EQ(1, nd.refIn.size()); +	ASSERT_EQ(1U, nd.refIn.size()); -	nd.incrDegree(RefDir::IN, n2); +	nd.incrDegree(Manager::RefDir::IN, n2);  	ASSERT_EQ(3, nd.refInCount());  	ASSERT_EQ(2, nd.refInCount(n1));  	ASSERT_EQ(1, nd.refInCount(n2)); -	ASSERT_EQ(2, nd.refIn.size()); +	ASSERT_EQ(2U, nd.refIn.size()); -	nd.incrDegree(RefDir::IN, nullptr); +	nd.incrDegree(Manager::RefDir::IN, nullptr);  	ASSERT_EQ(4, nd.refInCount());  	ASSERT_EQ(2, nd.refInCount(n1));  	ASSERT_EQ(1, nd.refInCount(n2)); -	ASSERT_EQ(2, nd.refIn.size()); +	ASSERT_EQ(2U, nd.refIn.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::IN, n1)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::IN, n1));  	ASSERT_EQ(3, nd.refInCount());  	ASSERT_EQ(1, nd.refInCount(n1));  	ASSERT_EQ(1, nd.refInCount(n2)); -	ASSERT_EQ(2, nd.refIn.size()); +	ASSERT_EQ(2U, nd.refIn.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::IN, n1)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::IN, n1));  	ASSERT_EQ(2, nd.refInCount());  	ASSERT_EQ(0, nd.refInCount(n1));  	ASSERT_EQ(1, nd.refInCount(n2)); -	ASSERT_EQ(1, nd.refIn.size()); +	ASSERT_EQ(1U, nd.refIn.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::IN, n2)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::IN, n2));  	ASSERT_EQ(1, nd.refInCount());  	ASSERT_EQ(0, nd.refInCount(n1));  	ASSERT_EQ(0, nd.refInCount(n2)); -	ASSERT_EQ(0, nd.refIn.size()); +	ASSERT_EQ(0U, nd.refIn.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::IN, nullptr)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::IN, nullptr));  	ASSERT_EQ(0, nd.refInCount());  	ASSERT_EQ(0, nd.refInCount(n1));  	ASSERT_EQ(0, nd.refInCount(n2)); -	ASSERT_EQ(0, nd.refIn.size()); +	ASSERT_EQ(0U, nd.refIn.size());  	// Output degree -	ASSERT_EQ(0, nd.refOut.size()); +	ASSERT_EQ(0U, nd.refOut.size());  	ASSERT_EQ(0, nd.refOutCount(n1)); -	nd.incrDegree(RefDir::OUT, n1); +	nd.incrDegree(Manager::RefDir::OUT, n1);  	ASSERT_EQ(1, nd.refOutCount());  	ASSERT_EQ(1, nd.refOutCount(n1));  	ASSERT_EQ(0, nd.refOutCount(n2)); -	ASSERT_EQ(1, nd.refOut.size()); +	ASSERT_EQ(1U, nd.refOut.size()); -	nd.incrDegree(RefDir::OUT, n1); +	nd.incrDegree(Manager::RefDir::OUT, n1);  	ASSERT_EQ(2, nd.refOutCount());  	ASSERT_EQ(2, nd.refOutCount(n1));  	ASSERT_EQ(0, nd.refOutCount(n2)); -	ASSERT_EQ(1, nd.refOut.size()); +	ASSERT_EQ(1U, nd.refOut.size()); -	nd.incrDegree(RefDir::OUT, n2); +	nd.incrDegree(Manager::RefDir::OUT, n2);  	ASSERT_EQ(3, nd.refOutCount());  	ASSERT_EQ(2, nd.refOutCount(n1));  	ASSERT_EQ(1, nd.refOutCount(n2)); -	ASSERT_EQ(2, nd.refOut.size()); +	ASSERT_EQ(2U, nd.refOut.size()); -	nd.incrDegree(RefDir::OUT, nullptr); +	nd.incrDegree(Manager::RefDir::OUT, nullptr);  	ASSERT_EQ(3, nd.refOutCount());  	ASSERT_EQ(2, nd.refOutCount(n1));  	ASSERT_EQ(1, nd.refOutCount(n2)); -	ASSERT_EQ(2, nd.refOut.size()); +	ASSERT_EQ(2U, nd.refOut.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n1)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::OUT, n1));  	ASSERT_EQ(2, nd.refOutCount());  	ASSERT_EQ(1, nd.refOutCount(n1));  	ASSERT_EQ(1, nd.refOutCount(n2)); -	ASSERT_EQ(2, nd.refOut.size()); +	ASSERT_EQ(2U, nd.refOut.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n1)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::OUT, n1));  	ASSERT_EQ(1, nd.refOutCount());  	ASSERT_EQ(0, nd.refOutCount(n1));  	ASSERT_EQ(1, nd.refOutCount(n2)); -	ASSERT_EQ(1, nd.refOut.size()); +	ASSERT_EQ(1U, nd.refOut.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::OUT, n2)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::OUT, n2));  	ASSERT_EQ(0, nd.refOutCount());  	ASSERT_EQ(0, nd.refOutCount(n1));  	ASSERT_EQ(0, nd.refOutCount(n2)); -	ASSERT_EQ(0, nd.refOut.size()); +	ASSERT_EQ(0U, nd.refOut.size()); -	ASSERT_TRUE(nd.decrDegree(RefDir::OUT, nullptr)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::OUT, nullptr));  	ASSERT_EQ(0, nd.refOutCount());  	ASSERT_EQ(0, nd.refOutCount(n1));  	ASSERT_EQ(0, nd.refOutCount(n2)); -	ASSERT_EQ(0, nd.refOut.size()); +	ASSERT_EQ(0U, nd.refOut.size());  }  TEST(ObjectDescriptor, rootRefCount)  { -	ObjectDescriptor nd; +	TestObjectDescriptor nd;  	ASSERT_EQ(0, nd.rootRefCount); -	nd.incrDegree(RefDir::IN, nullptr); +	nd.incrDegree(Manager::RefDir::IN, nullptr);  	ASSERT_EQ(1, nd.rootRefCount); -	nd.incrDegree(RefDir::OUT, nullptr); +	nd.incrDegree(Manager::RefDir::OUT, nullptr);  	ASSERT_EQ(2, nd.rootRefCount);  	ASSERT_EQ(2, nd.refInCount(nullptr)); @@ -159,13 +202,13 @@ TEST(ObjectDescriptor, rootRefCount)  	ASSERT_EQ(0, nd.refOutCount(nullptr));  	ASSERT_EQ(0, nd.refOutCount()); -	ASSERT_TRUE(nd.decrDegree(RefDir::OUT, nullptr)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::OUT, nullptr));  	ASSERT_EQ(1, nd.rootRefCount); -	ASSERT_TRUE(nd.decrDegree(RefDir::IN, nullptr)); +	ASSERT_TRUE(nd.decrDegree(Manager::RefDir::IN, nullptr));  	ASSERT_EQ(0, nd.rootRefCount); -	ASSERT_FALSE(nd.decrDegree(RefDir::IN, nullptr)); +	ASSERT_FALSE(nd.decrDegree(Manager::RefDir::IN, nullptr));  	ASSERT_EQ(0, nd.rootRefCount);  } @@ -436,7 +479,7 @@ TEST(Manager, disconnectDoubleRootedSubgraph)  }  Rooted<TestManaged> createFullyConnectedGraph(Manager &mgr, int nElem, -                                             bool alive[]) +                                              bool alive[])  {  	std::vector<Rooted<TestManaged>> nodes; @@ -474,18 +517,13 @@ TEST(Manager, fullyConnectedGraph)  }  class HidingTestManaged : public TestManaged { -  private:  	Rooted<Managed> hidden;  public: +	HidingTestManaged(Manager &mgr, bool &alive) : TestManaged(mgr, alive){}; -	HidingTestManaged(Manager &mgr, bool &alive) : TestManaged(mgr, alive) {}; - -	void setHiddenRef(Handle<Managed> t) { -		hidden = t; -	} - +	void setHiddenRef(Handle<Managed> t) { hidden = t; }  };  TEST(Manager, hiddenRootedGraph) @@ -510,6 +548,5 @@ TEST(Manager, hiddenRootedGraph)  		ASSERT_FALSE(v);  	}  } -  } diff --git a/test/core/TestManaged.hpp b/test/core/managed/TestManaged.hpp index 3b93e51..ed51c3b 100644 --- a/test/core/TestManaged.hpp +++ b/test/core/managed/TestManaged.hpp @@ -19,7 +19,7 @@  #ifndef _TEST_MANAGED_H_  #define _TEST_MANAGED_H_ -#include <core/Managed.hpp> +#include <core/managed/Managed.hpp>  namespace ousia { | 
