1
0
forked from 0ad/0ad
0ad/source/scriptinterface/third_party/ObjectToIDMap.h
2016-09-24 13:48:11 +00:00

133 lines
3.1 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Providing a map-like structure with JSObject pointers (actually their hash) as keys
* with correct garbage collection handling (JSObjects can move in memory).
*
* The code in this class was copied from here and modified to work in our environment.
* * https://mxr.mozilla.org/mozilla-esr38/source/js/ipc/JavaScriptShared.h
* * https://mxr.mozilla.org/mozilla-esr38/source/js/ipc/JavaScriptShared.cpp
*
* When updating SpiderMonkey, you most likely have to reintegrate an updated version
* of the class(es) in this file. The best way is probably to get a diff between the
* original files and integrate that because this file is heavily modified from the
* original version.
*/
#ifndef INCLUDED_OBJECTTOIDMAP
#define INCLUDED_OBJECTTOIDMAP
#include "scriptinterface/ScriptRuntime.h"
#include "scriptinterface/ScriptTypes.h"
#include <stdint.h>
// Map JSObjects -> ids
template <typename T>
class ObjectIdCache
{
typedef js::PointerHasher<JSObject*, 3> Hasher;
typedef js::HashMap<JSObject*, T, Hasher, js::SystemAllocPolicy> Table;
NONCOPYABLE(ObjectIdCache);
public:
ObjectIdCache(shared_ptr<ScriptRuntime> rt)
: table_(nullptr), m_rt(rt)
{
}
~ObjectIdCache()
{
if (table_)
{
m_rt->AddDeferredFinalizationObject(std::shared_ptr<void>((void*)table_, DeleteTable));
table_ = nullptr;
JS_RemoveExtraGCRootsTracer(m_rt->m_rt, ObjectIdCache::Trace, this);
}
}
bool init()
{
if (table_)
return true;
table_ = new Table(js::SystemAllocPolicy());
JS_AddExtraGCRootsTracer(m_rt->m_rt, ObjectIdCache::Trace, this);
return table_ && table_->init(32);
}
void trace(JSTracer* trc)
{
for (typename Table::Enum e(*table_); !e.empty(); e.popFront())
{
JSObject* obj = e.front().key();
JS_CallUnbarrieredObjectTracer(trc, &obj, "ipc-object");
if (obj != e.front().key())
e.rekeyFront(obj);
}
}
// TODO sweep?
bool find(JSObject* obj, T& ret)
{
typename Table::Ptr p = table_->lookup(obj);
if (!p)
return false;
ret = p->value();
return true;
}
bool add(JSContext* cx, JSObject* obj, T id)
{
if (!table_->put(obj, id))
return false;
JS_StoreObjectPostBarrierCallback(cx, keyMarkCallback, obj, table_);
return true;
}
void remove(JSObject* obj)
{
table_->remove(obj);
}
// TODO clear?
bool empty()
{
return table_->empty();
}
bool has(JSObject* obj)
{
return table_->has(obj);
}
private:
static void keyMarkCallback(JSTracer* trc, JSObject* key, void* data)
{
Table* table = static_cast<Table*>(data);
JSObject* prior = key;
JS_CallUnbarrieredObjectTracer(trc, &key, "ObjectIdCache::table_ key");
table->rekeyIfMoved(prior, key);
}
static void Trace(JSTracer* trc, void* data)
{
reinterpret_cast<ObjectIdCache*>(data)->trace(trc);
}
static void DeleteTable(void* table)
{
delete (Table*)table;
}
shared_ptr<ScriptRuntime> m_rt;
Table* table_;
};
#endif // INCLUDED_OBJECTTOIDMAP