blob: 9ff809d4f1b984d469cf2cd86f5e55f6290b79f2 [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 "Debug.h"
#include "mozincludes.h"
class LocalObjectTable {
private:
static const int INITIAL_OBJECT_TABLE_SIZE = 300;
int nextFree;
std::vector<NPObject*> objects;
bool dontFree;
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;
}
public:
LocalObjectTable() {
nextFree = -1;
objects.reserve(INITIAL_OBJECT_TABLE_SIZE);
dontFree = false;
}
virtual ~LocalObjectTable();
/**
* Add a new object, which must not be in the table, and return a new id for it.
*/
int add(NPObject* obj) {
int 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);
}
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;
}
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