|  | #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 |