mirror of https://github.com/KLayout/klayout.git
535 lines
12 KiB
C++
535 lines
12 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2023 Matthias Koefferlein
|
|
|
|
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 2 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, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef HDR_dbUserObject
|
|
#define HDR_dbUserObject
|
|
|
|
#include "dbCommon.h"
|
|
|
|
#include "dbTypes.h"
|
|
#include "dbPoint.h"
|
|
#include "dbTrans.h"
|
|
#include "dbObjectTag.h"
|
|
#include "dbBox.h"
|
|
#include "dbMemStatistics.h"
|
|
#include "tlClassRegistry.h"
|
|
|
|
#include <string>
|
|
#include <string.h>
|
|
|
|
namespace db {
|
|
|
|
template <class Coord> class generic_repository;
|
|
class ArrayRepository;
|
|
|
|
/**
|
|
* @brief Deliver unique and incremental class ID's (once)
|
|
*/
|
|
DB_PUBLIC unsigned int get_unique_user_object_class_id ();
|
|
|
|
/**
|
|
* @brief The base class for the user object class
|
|
*
|
|
* Each user object class must implement this interface
|
|
* in order to be able to be put into a user_object<C>.
|
|
*/
|
|
template <class C>
|
|
class DB_PUBLIC_TEMPLATE user_object_base
|
|
{
|
|
public:
|
|
typedef C coord_type;
|
|
|
|
virtual ~user_object_base () { }
|
|
|
|
/**
|
|
* @brief Compare with another object
|
|
*
|
|
* The implementation is supposed to return true if the
|
|
* object is identical to this. The pointer passed should be
|
|
* dynamic_cast to the derived class and false should be
|
|
* returned if the class is not identical.
|
|
*/
|
|
virtual bool equals (const user_object_base<C> *d) const = 0;
|
|
|
|
/**
|
|
* @brief Compare with another object
|
|
*
|
|
* The implementation is supposed to return true if the
|
|
* object is "less" to this. The pointer passed should be
|
|
* dynamic_cast to the derived class and it is guaranteed that
|
|
* this is possible.
|
|
*/
|
|
virtual bool less (const user_object_base<C> *d) const = 0;
|
|
|
|
/**
|
|
* @brief Return a unique class Id
|
|
*
|
|
* This value must be "some" unique class ID.
|
|
* This is either an integer assigned by convention or by calling
|
|
* get_unique_user_object_class_id once in the initialisation of a static member
|
|
* Used for operator< () implementation.
|
|
*/
|
|
virtual unsigned int class_id () const = 0;
|
|
|
|
/**
|
|
* @brief Clone the object
|
|
*
|
|
* This method is supposed to return a pointer to a new
|
|
* object identical to this one.
|
|
*/
|
|
virtual user_object_base<C> *clone () const = 0;
|
|
|
|
/**
|
|
* @brief Compute the bounding box of this object
|
|
*
|
|
* This method is supposed to return the bounding box
|
|
* of this object.
|
|
*/
|
|
virtual db::box<C> box () const = 0;
|
|
|
|
/**
|
|
* @brief Transform this object with a simple_trans
|
|
*/
|
|
virtual void transform (const simple_trans<C> &t)
|
|
{
|
|
transform (complex_trans<C, C> (t));
|
|
}
|
|
|
|
/**
|
|
* @brief Transform this object with a fixpoint_trans
|
|
*/
|
|
virtual void transform (const fixpoint_trans<C> &t)
|
|
{
|
|
transform (complex_trans<C, C> (t));
|
|
}
|
|
|
|
/**
|
|
* @brief Transform this object with a complex_trans
|
|
*/
|
|
virtual void transform (const complex_trans<C, C> & /*t*/)
|
|
{
|
|
// .. the default implementation does nothing ..
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the class name
|
|
*
|
|
* This class name can be used to construct an object from a string using the generic factory.
|
|
* The class name can be 0 indicating that it is not possible to create an object from a string
|
|
* and that the object is not registered in the generic factory.
|
|
*/
|
|
virtual const char *class_name () const { return 0; }
|
|
|
|
/**
|
|
* @brief Fill from a string
|
|
*
|
|
* This method needs to be implemented mainly if the object is to be created from the
|
|
* generic factory.
|
|
*/
|
|
virtual void from_string (const char * /*str*/, const char * /*base_path*/) { }
|
|
|
|
/**
|
|
* @brief Convert to a string
|
|
*
|
|
* This method needs to be implemented mainly if the object is to be created from the
|
|
* generic factory.
|
|
*/
|
|
virtual std::string to_string () const { return std::string (); }
|
|
|
|
/**
|
|
* @brief Collect memory statistics
|
|
*/
|
|
virtual void mem_stat (db::MemStatistics * /*stat*/, db::MemStatistics::purpose_t /*purpose*/, int /*cat*/, bool /*no_self*/, void * /*parent*/) const { }
|
|
};
|
|
|
|
template <class C>
|
|
class user_object
|
|
{
|
|
public:
|
|
typedef C coord_type;
|
|
typedef db::box<C> box_type;
|
|
typedef db::point<C> point_type;
|
|
typedef db::object_tag< user_object<C> > tag;
|
|
|
|
/**
|
|
* @brief The default constructor.
|
|
*
|
|
* The default constructor creates an empty object.
|
|
*/
|
|
user_object ()
|
|
: mp_obj (0)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The constructor taking a pointer to a base object
|
|
*
|
|
* This constructor takes over the ownership over the object
|
|
* passed.
|
|
*/
|
|
user_object (user_object_base<C> *obj)
|
|
: mp_obj (obj)
|
|
{
|
|
// .. nothing else ..
|
|
}
|
|
|
|
/**
|
|
* @brief The copy constructor
|
|
*/
|
|
user_object (const user_object<C> &d)
|
|
: mp_obj (0)
|
|
{
|
|
if (d.mp_obj) {
|
|
set_ptr (d.mp_obj->clone ());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief The move constructor
|
|
*/
|
|
user_object (user_object<C> &&d)
|
|
: mp_obj (0)
|
|
{
|
|
if (d.mp_obj) {
|
|
set_ptr (d.mp_obj);
|
|
d.mp_obj = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Assignment operator
|
|
*/
|
|
user_object<C> &operator= (const user_object<C> &d)
|
|
{
|
|
if (d.mp_obj) {
|
|
set_ptr (d.mp_obj->clone ());
|
|
} else {
|
|
set_ptr (0);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief Assignment operator (move)
|
|
*/
|
|
user_object<C> &operator= (user_object<C> &&d)
|
|
{
|
|
if (d.mp_obj) {
|
|
set_ptr (d.mp_obj);
|
|
d.mp_obj = 0;
|
|
} else {
|
|
set_ptr (0);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* @brief The destructor
|
|
*/
|
|
~user_object ()
|
|
{
|
|
set_ptr (0);
|
|
}
|
|
|
|
/**
|
|
* @brief The (dummy) translation operator
|
|
*/
|
|
void translate (const user_object<C> &d, db::generic_repository<C> &, db::ArrayRepository &)
|
|
{
|
|
*this = d;
|
|
}
|
|
|
|
/**
|
|
* @brief The (dummy) translation operator with transformation
|
|
*/
|
|
template <class T>
|
|
void translate (const user_object<C> &d, const T &t, db::generic_repository<C> &, db::ArrayRepository &)
|
|
{
|
|
*this = d;
|
|
transform (t);
|
|
}
|
|
|
|
/**
|
|
* @brief Equality test
|
|
*/
|
|
bool operator== (const user_object<C> &d) const
|
|
{
|
|
if (mp_obj == 0 || d.mp_obj == 0) {
|
|
return mp_obj == d.mp_obj;
|
|
} else {
|
|
return mp_obj->equals (d.mp_obj);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Inequality test
|
|
*/
|
|
bool operator!= (const user_object<C> &b) const
|
|
{
|
|
return !operator== (b);
|
|
}
|
|
|
|
/**
|
|
* @brief Less operator implementation
|
|
*/
|
|
bool operator< (const user_object<C> &b) const
|
|
{
|
|
if (mp_obj == 0 || b.mp_obj == 0) {
|
|
return mp_obj < b.mp_obj;
|
|
}
|
|
if (mp_obj->class_id () != b.mp_obj->class_id ()) {
|
|
return (mp_obj->class_id () < b.mp_obj->class_id ());
|
|
}
|
|
return mp_obj->less (b.mp_obj);
|
|
}
|
|
|
|
/**
|
|
* @brief Get the pointer to the base object
|
|
*/
|
|
const user_object_base<C> *ptr () const
|
|
{
|
|
return mp_obj;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the pointer to the base object (non-const version)
|
|
*/
|
|
user_object_base<C> *ptr ()
|
|
{
|
|
return mp_obj;
|
|
}
|
|
|
|
/**
|
|
* @brief Replace the pointer
|
|
*/
|
|
void set_ptr (user_object_base<C> *ptr)
|
|
{
|
|
if (mp_obj) {
|
|
delete mp_obj;
|
|
}
|
|
mp_obj = ptr;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the bounding box
|
|
*
|
|
* This may cause coordinate overflow if the user object cannot be represented
|
|
* in the target coordinate types.
|
|
*/
|
|
db::box<C> box () const
|
|
{
|
|
if (mp_obj) {
|
|
return mp_obj->box ();
|
|
} else {
|
|
return db::box<C> ();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Transform the object with the given transformation
|
|
*
|
|
* @param t The transformation to apply.
|
|
* The actual behaviour is implemented by the base object.
|
|
*/
|
|
template <class Trans>
|
|
void transform (const Trans &t)
|
|
{
|
|
if (mp_obj) {
|
|
mp_obj->transform (t);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Return the transformed object
|
|
*
|
|
* @param t The transformation to apply.
|
|
* The actual behaviour is implemented by the base object.
|
|
*/
|
|
template <class Trans>
|
|
db::user_object<C> transformed (const Trans &t) const
|
|
{
|
|
user_object o (*this);
|
|
o.transform (t);
|
|
return o;
|
|
}
|
|
|
|
/**
|
|
* @brief swap with another object
|
|
*/
|
|
void swap (db::user_object<C> &other)
|
|
{
|
|
std::swap (mp_obj, other.mp_obj);
|
|
}
|
|
|
|
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
|
{
|
|
if (! no_self) {
|
|
stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat);
|
|
}
|
|
if (mp_obj) {
|
|
mp_obj->mem_stat (stat, purpose, cat, false, (void *) this);
|
|
}
|
|
}
|
|
|
|
private:
|
|
db::user_object_base<C> *mp_obj;
|
|
};
|
|
|
|
/**
|
|
* @brief The standard user object base class typedef
|
|
*/
|
|
typedef user_object_base<db::Coord> UserObjectBase;
|
|
|
|
/**
|
|
* @brief The double coordinate user object base class typedef
|
|
*/
|
|
typedef user_object_base<db::DCoord> DUserObjectBase;
|
|
|
|
/**
|
|
* @brief The standard user object typedef
|
|
*/
|
|
typedef user_object<db::Coord> UserObject;
|
|
|
|
/**
|
|
* @brief The double coordinate user object typedef
|
|
*/
|
|
typedef user_object<db::DCoord> DUserObject;
|
|
|
|
/**
|
|
* @brief The base object of a factory-instantiable object
|
|
*/
|
|
template <class C>
|
|
class DB_PUBLIC_TEMPLATE user_object_factory_base
|
|
{
|
|
public:
|
|
user_object_factory_base () { }
|
|
virtual ~user_object_factory_base () { }
|
|
virtual const char *class_name () const = 0;
|
|
virtual user_object_base<C> *create () const = 0;
|
|
};
|
|
|
|
/**
|
|
* @brief An implementation of a user object factory
|
|
*
|
|
* This implements a factory for objects of class X with coordinate base type C.
|
|
*/
|
|
template <class X, class C>
|
|
class DB_PUBLIC_TEMPLATE user_object_factory_impl
|
|
: public user_object_factory_base <C>
|
|
{
|
|
public:
|
|
user_object_factory_impl (const char *class_name)
|
|
: mp_class_name (class_name)
|
|
{ }
|
|
|
|
virtual const char *class_name () const
|
|
{
|
|
return mp_class_name;
|
|
}
|
|
|
|
virtual user_object_base<C> *create () const
|
|
{
|
|
return new X ();
|
|
}
|
|
|
|
public:
|
|
const char *mp_class_name;
|
|
};
|
|
|
|
/**
|
|
* @brief The generic factory
|
|
*
|
|
* This factory creates an user object from a given string and class name.
|
|
*/
|
|
template <class C>
|
|
class user_object_factory
|
|
: public tl::Registrar< user_object_factory_base<C> >
|
|
{
|
|
public:
|
|
/**
|
|
* @brief Create a UserObject from a string with the given class and using the provided string to create the object from.
|
|
*
|
|
* If the class name is not registered, no object is created and 0 is returned.
|
|
*/
|
|
static user_object_base<C> *create (const char *class_name, const char *string, const char *base_path)
|
|
{
|
|
tl::Registrar< user_object_factory_base<C> > *factory = tl::Registrar< user_object_factory_base<C> >::get_instance ();
|
|
if (factory != 0) {
|
|
for (typename tl::Registrar< user_object_factory_base<C> >::iterator i = factory->begin (); i != factory->end (); ++i) {
|
|
if (strcmp (class_name, i->class_name ()) == 0) {
|
|
user_object_base<C> *obj = i->create ();
|
|
obj->from_string (string, base_path);
|
|
return obj;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Collect memory statistics
|
|
*/
|
|
template <class X>
|
|
inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, const user_object<X> &x, bool no_self = false, void *parent = 0)
|
|
{
|
|
x.mem_stat (stat, purpose, cat, no_self, parent);
|
|
}
|
|
|
|
/**
|
|
* @brief typedef for a factory object for integer coordinate user objects
|
|
*/
|
|
typedef user_object_factory<db::Coord> UserObjectFactory;
|
|
|
|
/**
|
|
* @brief typedef for a factory object for integer coordinate user objects
|
|
*/
|
|
typedef tl::RegisteredClass<user_object_factory_base<db::Coord> > UserObjectDeclaration;
|
|
|
|
/**
|
|
* @brief typedef for a factory object for double coordinate user objects
|
|
*/
|
|
typedef user_object_factory<db::DCoord> DUserObjectFactory;
|
|
|
|
/**
|
|
* @brief typedef for a factory object for double coordinate user objects
|
|
*/
|
|
typedef tl::RegisteredClass<user_object_factory_base<db::DCoord> > DUserObjectDeclaration;
|
|
|
|
} // namespace db
|
|
|
|
// inject a swap specialization into the std namespace:
|
|
namespace std
|
|
{
|
|
template <class C>
|
|
inline void swap (db::user_object<C> &a, db::user_object<C> &b)
|
|
{
|
|
a.swap (b);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|