Skip to content

Commit

Permalink
void* WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Borthwick committed Oct 26, 2015
1 parent b35874b commit 64cbcdd
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 240 deletions.
4 changes: 4 additions & 0 deletions GCPointer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
9301146E1BC8033E00ED2D6F /* SharedPtrTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SharedPtrTest.cpp; sourceTree = "<group>"; };
930114701BC8070100ED2D6F /* GCPointerCastingTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCPointerCastingTest.cpp; sourceTree = "<group>"; };
930114721BC808AC00ED2D6F /* GCPointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GCPointer.cpp; path = src/GCPointer.cpp; sourceTree = "<group>"; };
93068DFA1BDE7F4700CAD319 /* GCPool.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GCPool.h; path = src/GCPool.h; sourceTree = "<group>"; };
93068DFB1BDE7FEC00CAD319 /* GarbageCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GarbageCollection.h; path = src/GarbageCollection.h; sourceTree = "<group>"; };
93B72EC81BC07E24001F5870 /* GCPointer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = GCPointer; sourceTree = BUILT_PRODUCTS_DIR; };
93B72ECB1BC07E24001F5870 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
93B72ED21BC07E8F001F5870 /* GCPointerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GCPointerTest.cpp; path = ../GCPointer/test/GCPointerTest.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -118,6 +120,8 @@
93B72ED41BC07EC4001F5870 /* GCPointer.h */,
93B72F4F1BC31996001F5870 /* Containers.h */,
930114721BC808AC00ED2D6F /* GCPointer.cpp */,
93068DFA1BDE7F4700CAD319 /* GCPool.h */,
93068DFB1BDE7FEC00CAD319 /* GarbageCollection.h */,
);
path = GCPointer;
sourceTree = "<group>";
Expand Down
245 changes: 30 additions & 215 deletions GCPointer/src/GCPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,21 @@ namespace gc
{
public:
using OwnerType = Object;
protected:

// TODO: Private
public:
static const OwnerType* cNoOwner;
const OwnerType* owner;

class impl_class {
public:
void* to;
uint refCount;
bool marked;
// TODO: Needs destructor?
} *impl;

gc_ptr_base(const OwnerType* owner, impl_class* impl) : impl(impl) {}
};

// Forward declarations for friendship
Expand All @@ -35,8 +48,7 @@ namespace gc
private:
// Constructors
gc_ptr(const OwnerType* owner, T* to)
: owner(owner)
, impl(to ? new impl_class({ to, 1 , false }) : nullptr)
: gc_ptr_base(owner, to ? new impl_class({ to, 1 , false }) : nullptr)
{}

public:
Expand All @@ -46,30 +58,35 @@ namespace gc

// Copy constructor
gc_ptr(gc_ptr const& other)
: owner(other.owner)
, impl(nullptr)
: gc_ptr_base(other.owner, nullptr)
{
retain(other.impl);
}

// Move constructor
gc_ptr(gc_ptr&& other)
: owner(other.owner)
, impl(std::move(other.impl))
: gc_ptr_base(other.owner, std::move(other.impl))
{
other.impl = nullptr;
}

template<typename OtherT>
gc_ptr(gc_ptr<OtherT> const& other)
: gc_ptr_base(other.owner, nullptr)
{
retain(other.impl);
}

~gc_ptr()
{
gc_pool<T>::sInstance.remove(*this);
release();
}

T* get() { return impl ? impl->to : nullptr; }
const T* get() const { return impl ? impl->to : nullptr; }
T* get() { return impl ? (T*)impl->to : nullptr; }
const T* get() const { return impl ? (T*)impl->to : nullptr; }
T* operator->() { return get(); }
T& operator*() { return *impl->to; }
T& operator*() { return *get(); }

gc_ptr<T>& operator=(gc_ptr<T> const& other)
{
Expand Down Expand Up @@ -110,24 +127,10 @@ namespace gc

std::string to_string() const
{
return std::string("gc_ptr{ ") + (impl ? impl->to->to_string() : " null ") + " }";
return std::string("gc_ptr{ ") + (impl ? to_string(*impl->to) : " null ") + " }";
}

private:
const OwnerType* owner;

class impl_class {
public:
~impl_class()
{
delete to;
}

T* to;
uint refCount;
bool marked;
} *impl;

void retain(impl_class* newImpl)
{
if (newImpl)
Expand All @@ -140,200 +143,12 @@ namespace gc
{
if (impl && --impl->refCount == 0)
{
delete (T*) impl->to;
impl->to = nullptr;
delete impl;
}

impl = nullptr;
}
};

template<typename T>
class gc_pool
{
public:
using Ptr = gc_ptr<T>;
using OwnerType = gc_ptr_base::OwnerType;
friend class gc_ptr<T>;
static gc_pool<T> sInstance;

template<typename... ARGS>
Ptr makeUnowned(ARGS... args)
{
return makeOwned(Ptr::cNoOwner, std::forward<ARGS>(args)...);
}

Ptr makeUnownedFromInstance(T* instance)
{
Ptr p { Ptr::cNoOwner, instance };
add(p);
return p;
}

template<typename... ARGS>
Ptr makeOwned(const OwnerType* owner, ARGS... args)
{
Ptr p(owner, new T(std::forward<ARGS>(args)...));
add(p);
return p;
}

Ptr makeOwnedNull(OwnerType* owner)
{
Ptr p(owner, nullptr);
add(p);
return p;
}

void reset()
{
pointers.clear();
}

void collectGarbage()
{
unmarkAll();
mark(unownedPointers());
deleteUnmarked();
}

std::string to_string() const
{
std::string result = std::string("gc_pool<") + typeid(T).name() + "> { size: " + std::to_string(pointers.size());
for (auto it = pointers.begin(); it != pointers.end(); ++it)
{
result += "\n\t{ " + it->first->to_string() + ", " + it->second->to_string() + " }";
}
result += pointers.size() ? "\n}" : "}";

return result;
}

private:
using OwnerPointerMap = std::multimap<const OwnerType*, Ptr*>;
using MapIt = typename OwnerPointerMap::iterator;
using Range = std::pair<MapIt, MapIt>;

OwnerPointerMap pointers;

void add(Ptr& ptr)
{
pointers.insert({ ptr.owner, &ptr });
}

void remove(Ptr& ptr)
{
map_remove_if_value(pointers, [&](Ptr* candidate) {
return candidate == &ptr;
});
}

void mark(Range range)
{
for (MapIt it = range.first; it != range.second; ++it)
{
Ptr& ptr = *it->second;
if (ptr.impl)
{
if (ptr.impl->marked)
{
// Already encountered this part of the graph, terminate recursion
break;
}
else
ptr.impl->marked = true;
}

Range children = pointers.equal_range(ptr.get());
mark(children);
}
}

void deleteUnmarked()
{
for (auto it = pointers.begin(); it != pointers.end(); )
{
Ptr& ptr = *it->second;
if (ptr.impl && !ptr.impl->marked)
{
Object* pointee = ptr.get();
nullifyPointersTo(*ptr);

// TODO: Need to prevent this invalidating iterator
delete pointee;

// Iterator now invalid, start again
it = pointers.begin();
}
else
++it;
}
}

void nullifyPointersTo(OwnerType& pointee)
{
for (auto entry : pointers)
{
Ptr& p = *entry.second;
if (p.impl && (p.impl->to == &pointee))
{
p.impl = nullptr;
}
}
}

void unmarkAll()
{
for (auto entry : pointers)
{
Ptr& p = *entry.second;
if (p.impl)
{
p.impl->marked = false;
}
}
}

Range unownedPointers()
{
return pointers.equal_range(Ptr::cNoOwner);
}
};

template <typename T, typename... ARGS>
gc_ptr<T> make_gc(ARGS&&... args)
{
return gc_pool<T>::sInstance.makeUnowned(std::forward<ARGS>(args)...);
}

template <typename T, typename... ARGS>
gc_ptr<T> make_owned_null_gc(gc_ptr_base::OwnerType* owner)
{
return gc_pool<T>::sInstance.makeOwnedNull(owner);
}

template <typename T, typename... ARGS>
gc_ptr<T> make_owned_gc(gc_ptr_base::OwnerType* owner, ARGS&&... args)
{
return gc_pool<T>::sInstance.makeOwned(owner, std::forward<ARGS>(args)...);
}

template <typename T>
void collectGarbage()
{
gc_pool<T>::sInstance.collectGarbage();
}

template <class Base, class Derived>
gc_ptr<Derived> dynamic_pointer_cast(gc_ptr<Base>& base)
{
using DerivedImplClass = typename gc_ptr<Derived>::impl_class;
gc_ptr<Derived> derived;

if (dynamic_cast<Derived*>(base.get()))
{
derived.owner = base.owner;
derived.impl = (DerivedImplClass*)((void*)base.impl);
}
return derived;
}
}
Loading

0 comments on commit 64cbcdd

Please sign in to comment.