// OpenSTA, Static Timing Analyzer // Copyright (c) 2019, Parallax Software, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #ifndef STA_POOL_H #define STA_POOL_H #include #include // max #include "DisallowCopyAssign.hh" #include "Error.hh" #include "Vector.hh" #include "ObjectIndex.hh" namespace sta { using std::max; typedef Vector DeletedListHeads; template class PoolBlock { public: explicit PoolBlock(ObjectIndex size, ObjectIndex begin_index); OBJ *makeObject(); OBJ *makeObjects(ObjectIndex count); ObjectIndex index(const OBJ *object); OBJ *find(ObjectIndex index); PoolBlock *nextBlock() const { return next_block_; } void setNextBlock(PoolBlock *next); ObjectIndex size() const { return objects_.size(); } private: DISALLOW_COPY_AND_ASSIGN(PoolBlock); std::vector objects_; ObjectIndex begin_index_; ObjectIndex next_free_; PoolBlock *next_block_; static constexpr unsigned min_initial_size_ = 100; }; template PoolBlock::PoolBlock(ObjectIndex size, ObjectIndex begin_index) : objects_(size), begin_index_(begin_index), next_free_(0), next_block_(nullptr) { } template OBJ * PoolBlock::makeObject() { if (next_free_ < objects_.size()) return &objects_[next_free_++]; else return nullptr; } template OBJ * PoolBlock::makeObjects(ObjectIndex count) { if ((next_free_ + count - 1) < objects_.size()) { OBJ *object = &objects_[next_free_]; next_free_ += count; return object; } else return nullptr; } template ObjectIndex PoolBlock::index(const OBJ *object) { if (object >= &objects_[0] && object < &objects_[objects_.size()]) // Index==0 is reserved. return begin_index_ + object - &objects_[0] + 1; else return 0; } template OBJ * PoolBlock::find(ObjectIndex index) { // Index==0 is reserved. ObjectIndex index1 = index - 1; if (index1 >= begin_index_ && index1 < begin_index_ + objects_.size()) return &objects_[index1 - begin_index_]; else return nullptr; } template void PoolBlock::setNextBlock(PoolBlock *next) { next_block_ = next; } //////////////////////////////////////////////////////////////// template class Pool { public: Pool(); explicit Pool(ObjectIndex size); explicit Pool(ObjectIndex size, float growth_factor); ~Pool(); OBJ *makeObject(); OBJ *makeObjects(ObjectIndex count); void deleteObject(OBJ *object); void deleteObject(ObjectIndex index); void deleteObjects(OBJ *objects, ObjectIndex count); void deleteObjects(ObjectIndex index, ObjectIndex count); // Index=0 is reserved for the nullptr object pointer. ObjectIndex index(const OBJ *object) const; OBJ *find(ObjectIndex index) const; ObjectIndex size() const { return size_; } void clear(); protected: PoolBlock *makeBlock(ObjectIndex block_size); OBJ *findDeletedObject(ObjectIndex count); void deleteObjects(OBJ *object, ObjectIndex index, ObjectIndex count); ObjectIndex size_; float growth_factor_; PoolBlock *blocks_; PoolBlock *last_block_; // Index of deleted objects that are the head of a list indexed by // object array count. DeletedListHeads deleted_list_heads_; }; template Pool::Pool(ObjectIndex size) : Pool(size, .2F) { } template Pool::Pool(ObjectIndex size, float growth_factor) : size_(0), growth_factor_(growth_factor), blocks_(nullptr), last_block_(nullptr) { makeBlock(size); } template Pool::~Pool() { PoolBlock *next; for (PoolBlock *block = blocks_; block; block = next) { next = block->nextBlock(); delete block; } } template OBJ * Pool::makeObject() { OBJ *object = findDeletedObject(1); if (object == nullptr) { object = last_block_->makeObject(); if (object == nullptr) { ObjectIndex block_size=static_cast(size_*growth_factor_+2); PoolBlock *block = makeBlock(block_size); object = block->makeObject(); } } return object; } template OBJ * Pool::findDeletedObject(ObjectIndex count) { if (deleted_list_heads_.size() > count) { ObjectIndex index = deleted_list_heads_[count]; if (index) { OBJ *object = find(index); ObjectIndex next_index = *reinterpret_cast(object); deleted_list_heads_[count] = next_index; return object; } } return nullptr; } template OBJ * Pool::makeObjects(ObjectIndex count) { OBJ *objects = findDeletedObject(count); if (objects == nullptr) { objects = last_block_->makeObjects(count); if (objects == nullptr) { ObjectIndex block_size=max(static_cast(size_*growth_factor_+2), count); PoolBlock *block = makeBlock(block_size); objects = block->makeObjects(count); } } return objects; } template PoolBlock * Pool::makeBlock(ObjectIndex block_size) { PoolBlock *block = new PoolBlock(block_size, size_); // Add new block to end of block list so searches start with // the first block. if (last_block_) last_block_->setNextBlock(block); else blocks_ = block; last_block_ = block; size_ += block_size; return block; } template ObjectIndex Pool::index(const OBJ *object) const { if (object) { for (PoolBlock *block = blocks_; block; block = block->nextBlock()) { ObjectIndex index = block->index(object); if (index > 0) return index; } internalError("object index not found in pool"); return 0; } else return 0; } template OBJ * Pool::find(ObjectIndex index) const { if (index) { for (PoolBlock *block = blocks_; block; block = block->nextBlock()) { OBJ *object = block->find(index); if (object) return object; } internalError("object index not found in pool"); return nullptr; } else return nullptr; } template void Pool::deleteObject(OBJ *object) { deleteObjects(object, index(object), 1); } template void Pool::deleteObject(ObjectIndex index) { deleteObjects(find(index), index, 1); } template void Pool::deleteObjects(OBJ *objects, ObjectIndex count) { deleteObjects(objects, index(objects), count); } template void Pool::deleteObjects(ObjectIndex index, ObjectIndex count) { deleteObjects(find(index), index, count); } template void Pool::deleteObjects(OBJ *object, ObjectIndex index, ObjectIndex count) { if (deleted_list_heads_.size() <= count) deleted_list_heads_.resize(count + 1); ObjectIndex next_index = deleted_list_heads_[count]; *reinterpret_cast(object) = next_index; deleted_list_heads_[count] = index; } template void Pool::clear() { last_block_ = blocks_; last_block_->clear(); } } // Namespace #endif