#ifndef Supplementable_h
#define Supplementable_h
#include "heap/Handle.h"
#include "wtf/Assertions.h"
#include "wtf/HashMap.h"
#include "wtf/OwnPtr.h"
#include "wtf/PassOwnPtr.h"
#if !ASSERT_DISABLED
#include "wtf/Threading.h"
#endif
namespace WebCore {
template<typename T, bool isGarbageCollected>
class SupplementBase;
template<typename T, bool isGarbageCollected>
class SupplementableBase;
template<typename T, bool isGarbageCollected>
struct SupplementableTraits;
template<typename T>
struct SupplementableTraits<T, true> {
typedef RawPtr<SupplementBase<T, true> > SupplementArgumentType;
typedef HeapHashMap<const char*, Member<SupplementBase<T, true> >, PtrHash<const char*> > SupplementMap;
};
template<typename T>
struct SupplementableTraits<T, false> {
typedef PassOwnPtr<SupplementBase<T, false> > SupplementArgumentType;
typedef HashMap<const char*, OwnPtr<SupplementBase<T, false> >, PtrHash<const char*> > SupplementMap;
};
template<bool>
class SupplementTracing;
template<>
class SupplementTracing<true> : public GarbageCollectedMixin {
public:
virtual void trace(Visitor*) = 0;
};
template<>
class SupplementTracing<false> {
public:
virtual ~SupplementTracing() { }
};
template<typename T, bool isGarbageCollected = false>
class SupplementBase : public SupplementTracing<isGarbageCollected> {
public:
#if SECURITY_ASSERT_ENABLED
virtual bool isRefCountedWrapper() const { return false; }
#endif
static void provideTo(SupplementableBase<T, isGarbageCollected>& host, const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement)
{
host.provideSupplement(key, supplement);
}
static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>& host, const char* key)
{
return host.requireSupplement(key);
}
static SupplementBase<T, isGarbageCollected>* from(SupplementableBase<T, isGarbageCollected>* host, const char* key)
{
return host ? host->requireSupplement(key) : 0;
}
};
template<typename T, bool>
class SupplementableTracing;
template<typename T>
class SupplementableTracing<T, true> : public GarbageCollectedMixin {
public:
void trace(Visitor* visitor) { visitor->trace(m_supplements); }
private:
typename SupplementableTraits<T, true>::SupplementMap m_supplements;
friend class SupplementableBase<T, true>;
};
template<typename T>
class SupplementableTracing<T, false> {
private:
typename SupplementableTraits<T, false>::SupplementMap m_supplements;
friend class SupplementableBase<T, false>;
};
template<typename T, bool isGarbageCollected = false>
class SupplementableBase : public SupplementableTracing<T, isGarbageCollected> {
public:
void provideSupplement(const char* key, typename SupplementableTraits<T, isGarbageCollected>::SupplementArgumentType supplement)
{
ASSERT(m_threadId == currentThread());
ASSERT(!this->m_supplements.get(key));
this->m_supplements.set(key, supplement);
}
void removeSupplement(const char* key)
{
ASSERT(m_threadId == currentThread());
this->m_supplements.remove(key);
}
SupplementBase<T, isGarbageCollected>* requireSupplement(const char* key)
{
ASSERT(m_threadId == currentThread());
return this->m_supplements.get(key);
}
void reattachThread()
{
#if !ASSERT_DISABLED
m_threadId = currentThread();
#endif
}
#if !ASSERT_DISABLED
protected:
SupplementableBase() : m_threadId(currentThread()) { }
private:
ThreadIdentifier m_threadId;
#endif
};
template<typename T>
class HeapSupplement : public SupplementBase<T, true> { };
template<typename T>
class HeapSupplementable : public SupplementableBase<T, true> { };
template<typename T>
class Supplement : public SupplementBase<T, false> { };
template<typename T>
class Supplementable : public SupplementableBase<T, false> { };
template<typename T>
struct ThreadingTrait<WebCore::SupplementBase<T, true> > {
static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity;
};
template<typename T>
struct ThreadingTrait<WebCore::SupplementableBase<T, true> > {
static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity;
};
}
#endif