blob: 4943ff30b86bee83181e85af5347025b060f8d07 [file] [log] [blame]
#ifndef H_LocalObjectTable
#define H_LocalObjectTable
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#include <vector>
#include <algorithm>
#include <map>
#include "Debug.h"
#include "mozincludes.h"
class LocalObjectTable {
private:
static const int INITIAL_OBJECT_TABLE_SIZE = 300;
int nextFree;
std::vector<NPObject*> objects;
std::map<void*, int> objectIndex;
bool dontFree;
static NPClass* wrappedObjectClass;
bool isFree(int id) {
// low bit is set for free pointers, object pointers can't be odd
NPObject* obj = objects[id];
return !obj || (reinterpret_cast<long long>(obj) & 1);
}
void setFree(int id) {
objects[id] = reinterpret_cast<NPObject*>((nextFree << 1) | 1LL);
nextFree = id;
}
int findIndex(void* ptr) {
std::map<void*, int>::iterator it = objectIndex.find(ptr);
if (it == objectIndex.end()) {
return -1;
}
return it->second;
}
static void* getIdentityFrom(NPObject* obj);
public:
LocalObjectTable() {
nextFree = -1;
objects.reserve(INITIAL_OBJECT_TABLE_SIZE);
dontFree = false;
}
virtual ~LocalObjectTable();
static void setWrappedObjectClass(NPClass* clazz) {
wrappedObjectClass = clazz;
}
int add(NPObject* obj) {
void* objId = getIdentityFrom(obj);
int id = findIndex(objId);
if (id >= 0) {
Debug::log(Debug::Spam) << "LocalObjectTable::add(obj=" << obj
<< "): returning old id=" << id << Debug::flush;
return id;
}
if (nextFree >= 0) {
id = nextFree;
nextFree = int(reinterpret_cast<long long>(objects[nextFree])) >> 1;
objects[id] = obj;
} else {
id = static_cast<int>(objects.size());
objects.push_back(obj);
}
objectIndex[objId] = id;
Debug::log(Debug::Spam) << "LocalObjectTable::add(obj=" << obj << "): id=" << id
<< Debug::flush;
// keep track that we hold a reference in the table
NPN_RetainObject(obj);
return id;
}
int find(NPObject* obj) {
void* objId = getIdentityFrom(obj);
return findIndex(objId);
}
void free(int id) {
Debug::log(Debug::Spam) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
if (unsigned(id) >= objects.size()) {
Debug::log(Debug::Error) << "LocalObjectTable::free(id=" << id << "): invalid index (size="
<< objects.size() << Debug::flush;
return;
}
if (isFree(id)) {
Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush;
return;
}
NPObject* obj = objects[id];
setFree(id);
if (!dontFree) {
NPN_ReleaseObject(obj);
}
}
void freeAll() {
Debug::log(Debug::Spam) << "LocalObjectTable::freeAll()" << Debug::flush;
for (unsigned i = 0; i < objects.size(); ++i) {
if (!isFree(i)) {
NPObject* obj = objects[i];
setFree(i);
if (!dontFree) {
NPN_ReleaseObject(obj);
}
}
}
}
NPObject* get(int id) {
if (unsigned(id) >= objects.size()) {
Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id << "): invalid index (size="
<< objects.size() << Debug::flush;
return 0;
}
if (isFree(id)) {
Debug::log(Debug::Error) << "Getting freed object slot " << id << Debug::flush;
return 0;
}
return objects[id];
}
void setDontFree(bool dontFree) {
this->dontFree = dontFree;
}
};
#endif