// OpenSTA, Static Timing Analyzer
// Copyright (c) 2018, 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);
~PoolBlock();
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 size_; }
private:
DISALLOW_COPY_AND_ASSIGN(PoolBlock);
ObjectIndex size_;
ObjectIndex begin_index_;
OBJ *objects_;
ObjectIndex next_free_;
PoolBlock *next_block_;
};
template
PoolBlock::PoolBlock(ObjectIndex size,
ObjectIndex begin_index) :
size_(size),
begin_index_(begin_index),
objects_(new OBJ[size]),
next_free_(0),
next_block_(NULL)
{
}
template
PoolBlock::~PoolBlock()
{
delete [] objects_;
}
template
OBJ *
PoolBlock::makeObject()
{
if (next_free_ < size_)
return &objects_[next_free_++];
else
return NULL;
}
template
OBJ *
PoolBlock::makeObjects(ObjectIndex count)
{
if ((next_free_ + count - 1) < size_) {
OBJ *object = &objects_[next_free_];
next_free_ += count;
return object;
}
else
return NULL;
}
template
ObjectIndex
PoolBlock::index(const OBJ *object)
{
if (object >= objects_ && object < &objects_[size_])
// Index==0 is reserved.
return begin_index_ + object - objects_ + 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_ + size_)
return &objects_[index1 - begin_index_];
else
return NULL;
}
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 NULL 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) :
size_(0),
growth_factor_(.2F),
blocks_(NULL),
last_block_(NULL)
{
if (size > 0)
makeBlock(size);
}
template
Pool::Pool(ObjectIndex size,
float growth_factor) :
size_(0),
growth_factor_(growth_factor),
blocks_(NULL),
last_block_(NULL)
{
if (size > 0)
makeBlock(size);
}
template
Pool::~Pool()
{
PoolBlock *next;
for (PoolBlock *block = blocks_; block; block = next) {
next = block->nextBlock();
delete block;
}
}
template
OBJ *
Pool::makeObject()
{
if (size_ == 0)
makeBlock(10);
OBJ *object = findDeletedObject(1);
if (object == NULL) {
object = last_block_->makeObject();
if (object == NULL) {
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 (size_ == 0)
makeBlock(10);
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 NULL;
}
template
OBJ *
Pool::makeObjects(ObjectIndex count)
{
OBJ *objects = findDeletedObject(count);
if (objects == NULL) {
objects = last_block_->makeObjects(count);
if (objects == NULL) {
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 NULL;
}
else
return NULL;
}
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