OpenSTA/include/sta/ObjectTable.hh

215 lines
5.4 KiB
C++

// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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 <https://www.gnu.org/licenses/>.
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
#pragma once
#include "Vector.hh"
#include "Error.hh"
#include "ObjectId.hh"
namespace sta {
template <class OBJECT>
class TableBlock;
// Object tables allocate objects in blocks and use 32 bit IDs to
// reference an object. Paging performance is improved by allocating
// blocks instead of individual objects, and object sizes are reduced
// by using 32 bit references instead of 64 bit pointers.
//
// Class TYPE must define member functions
// ObjectIdx objectIdx() const
// void setObjectIdx(ObjectIdx idx)
// to get/set the index of the object in a block, which can be a bit
// field ObjectTable::idx_bits (7 bits) wide.
template <class TYPE>
class ObjectTable
{
public:
ObjectTable();
~ObjectTable();
TYPE *make();
void destroy(TYPE *object);
TYPE *pointer(ObjectId id) const;
TYPE &ref(ObjectId id) const;
ObjectId objectId(const TYPE *object);
size_t size() const { return size_; }
void clear();
// Objects are allocated in blocks of 128.
static constexpr int idx_bits = 7;
static constexpr int block_object_count = (1 << idx_bits);
static constexpr int block_id_max = 1 << (object_id_bits - idx_bits);
private:
void makeBlock();
void freePush(TYPE *object,
ObjectId id);
size_t size_;
// Object ID of next free object.
ObjectId free_;
Vector<TableBlock<TYPE>*> blocks_;
static constexpr ObjectId idx_mask_ = block_object_count - 1;
};
template <class TYPE>
ObjectTable<TYPE>::ObjectTable() :
size_(0),
free_(object_id_null)
{
}
template <class TYPE>
ObjectTable<TYPE>::~ObjectTable()
{
blocks_.deleteContents();
}
template <class TYPE>
TYPE *
ObjectTable<TYPE>::make()
{
if (free_ == object_id_null)
makeBlock();
TYPE *object = pointer(free_);
ObjectIdx idx = free_ & idx_mask_;
object->setObjectIdx(idx);
ObjectId *free_next = reinterpret_cast<ObjectId*>(object);
free_ = *free_next;
size_++;
return object;
}
template <class TYPE>
void
ObjectTable<TYPE>::freePush(TYPE *object,
ObjectId id)
{
// Link free objects into a list linked by Object ID.
ObjectId *free_next = reinterpret_cast<ObjectId*>(object);
*free_next = free_;
free_ = id;
}
template <class TYPE>
void
ObjectTable<TYPE>::makeBlock()
{
BlockIdx block_index = blocks_.size();
TableBlock<TYPE> *block = new TableBlock<TYPE>(block_index, this);
blocks_.push_back(block);
if (blocks_.size() >= block_id_max)
criticalError(224, "max object table block count exceeded.");
// ObjectId zero is reserved for object_id_null.
int last = (block_index > 0) ? 0 : 1;
for (int i = block_object_count - 1; i >= last; i--) {
TYPE *obj = block->pointer(i);
ObjectId id = (block_index << idx_bits) + i;
freePush(obj, id);
}
}
template <class TYPE>
TYPE *
ObjectTable<TYPE>::pointer(ObjectId id) const
{
if (id == object_id_null)
return nullptr;
else {
BlockIdx blk_idx = id >> idx_bits;
ObjectIdx obj_idx = id & idx_mask_;
return blocks_[blk_idx]->pointer(obj_idx);
}
}
template <class TYPE>
TYPE &
ObjectTable<TYPE>::ref(ObjectId id) const
{
if (id == object_id_null)
criticalError(225, "null ObjectId reference is undefined.");
else {
BlockIdx blk_idx = id >> idx_bits;
ObjectIdx obj_idx = id & idx_mask_;
return blocks_[blk_idx]->ptr(obj_idx);
}
}
template <class TYPE>
ObjectId
ObjectTable<TYPE>::objectId(const TYPE *object)
{
ObjectIdx idx = object->objectIdx();
const TableBlock<TYPE> *blk =
reinterpret_cast<const TableBlock<TYPE>*>(object - idx);
return (blk->index() << idx_bits) + idx;
}
template <class TYPE>
void
ObjectTable<TYPE>::destroy(TYPE *object)
{
ObjectId object_id = objectId(object);
size_--;
freePush(object, object_id);
}
template <class TYPE>
void
ObjectTable<TYPE>::clear()
{
blocks_.deleteContentsClear();
size_ = 0;
}
////////////////////////////////////////////////////////////////
template <class TYPE>
class TableBlock
{
public:
TableBlock(BlockIdx block_idx,
ObjectTable<TYPE> *table);
BlockIdx index() const { return block_idx_; }
TYPE &ref(ObjectIdx idx) { return objects_[idx]; }
TYPE *pointer(ObjectIdx idx) { return &objects_[idx]; }
private:
TYPE objects_[ObjectTable<TYPE>::block_object_count];
BlockIdx block_idx_;
ObjectTable<TYPE> *table_;
};
template <class TYPE>
TableBlock<TYPE>::TableBlock(BlockIdx block_idx,
ObjectTable<TYPE> *table) :
block_idx_(block_idx),
table_(table)
{
}
} // Namespace