340 lines
14 KiB
C++
340 lines
14 KiB
C++
// -*- C++ -*-
|
|
|
|
|
|
namespace Hurricane {
|
|
|
|
/*! \defgroup JsonSupport JSON Support
|
|
* \brief JSON Import/Export of the DataBase
|
|
*
|
|
* \section secJsonSupportIntro Introduction
|
|
*
|
|
* One key feature of the Hurricane DataBase is it's hierarchical
|
|
* managment. But unfortunatly the simple approach of saving a design
|
|
* Cell by Cell, hierarchical level by hierarchical level makes it
|
|
* very difficult to save the trans-hierarchical informations (mainly
|
|
* is the occurrences)
|
|
*
|
|
* One solution is to save the design and all it's levels, down and
|
|
* including the standard cells. With all the levels saved, we then
|
|
* can add the occurrences and all the attached trans-hierarchical
|
|
* informations. We call that comprehensive saving of a design,
|
|
* a <em>design blob</em>.
|
|
*
|
|
* Instead of creating one more ad-hoc format, we just dump the
|
|
* DataBase objects in a mirror like way in JSON format.
|
|
*
|
|
* As it is a textual format, the generated files are larges.
|
|
* So the files are compressed through \c gzip.
|
|
*
|
|
*
|
|
* \section secJsonSemantic JSON Additional Semantic
|
|
*
|
|
* To ease the work of the parser, some semantic has been added
|
|
* to the JSON objects representing a Hurricane DataBase.
|
|
* -# The first key/value pair must have the key \c "@typename"
|
|
* and give the kind of JsonObject associated. The value is
|
|
* the string returned by \c JsonObject::getTypeName().
|
|
* -# Attributes keys must start by a \c '_' character.
|
|
* (yes, I know, the C++ convention has changed and it should
|
|
* be put at the end).
|
|
* -# Collections or containers must be put \e after all the
|
|
* scalar attributes and their keys must start by a \c '+'
|
|
* character.
|
|
*
|
|
\code{.json}
|
|
{
|
|
"@typename": "Cell",
|
|
"_id": 3,
|
|
"_library": "RootLibrary.AllianceFramework.sxlib",
|
|
"_name": "o3_x2",
|
|
"_abutmentBox": {
|
|
"@typename": "Box",
|
|
"_xMin": 0,
|
|
"_yMin": 0,
|
|
"_xMax": 72000,
|
|
"_yMax": 120000
|
|
},
|
|
"+instanceMap": [],
|
|
"+netMap": [
|
|
],
|
|
}
|
|
\endcode
|
|
*
|
|
* \section secJsonDriver JSON Driver Support
|
|
*
|
|
* The driver is implemented through overloads (template and
|
|
* non-template) of the \c jsonWriter() function. For the
|
|
* template overload to work, even for non-Hurricane classes,
|
|
* it is defined outside the Hurricane namespace.
|
|
*
|
|
* For POD types, four overloads of \c jsonWriter() are defined:
|
|
*
|
|
\code
|
|
void jsonWrite ( JsonWriter* w, const int* v );
|
|
void jsonWrite ( JsonWriter* w, int v );
|
|
void jsonWrite ( JsonWriter* w, const std::string& key, const int* value )
|
|
void jsonWrite ( JsonWriter* w, const std::string& key, int value )
|
|
\endcode
|
|
*
|
|
* The first two writes the object (here: \c int) "as is" while
|
|
* the two later writes a pair key/object.
|
|
*
|
|
* For other class/object that needs to be writen in the JSON file,
|
|
* they must provide a \c toJson() function. It doesn't even need
|
|
* to be virtual. For Point:
|
|
*
|
|
\code
|
|
void Point::toJson ( JsonWriter* w ) const
|
|
{
|
|
w->startObject();
|
|
jsonWrite( w, "@typename", "Point" );
|
|
jsonWrite( w, "_x", getX() );
|
|
jsonWrite( w, "_y", getY() );
|
|
w->endObject();
|
|
}
|
|
\endcode
|
|
*
|
|
* This function allows three templates of \c jsonWrite() to be
|
|
* used with an object of class Point:
|
|
*
|
|
\code
|
|
template<typename C>
|
|
void jsonWrite ( JsonWriter* w, const C* object );
|
|
|
|
template<typename C>
|
|
void jsonWrite ( JsonWriter* w, const std::string& key, C* object );
|
|
|
|
template<typename C>
|
|
void jsonWrite ( JsonWriter* w, const std::string& key, const C* object );
|
|
\endcode
|
|
*
|
|
* Note that through those three overloads we only provides
|
|
* support for pointers to object. The driving mechanism is
|
|
* designed in such a way that passing arguments by value is
|
|
* not supported for non-POD types. Trying to do so will
|
|
* result in an unsupported message inside the generated
|
|
* JSON file.
|
|
*
|
|
*
|
|
* \subsection secJsonDriverDBo DBos Special Case
|
|
*
|
|
* For DBo objects, a complete parallel hierarchy of JsonObjects
|
|
* mimicking the one of DBos has been implemented. The \c toJson()
|
|
* function is implemented in the DBo base object, and the
|
|
* derived classes must implement the following virtual functions:
|
|
*
|
|
\code
|
|
class DBo {
|
|
public:
|
|
virtual void _toJson ( JsonWriter* ) const;
|
|
virtual void _toJsonCollections ( JsonWriter* ) const;
|
|
virtual void _toJsonSignature ( JsonWriter* ) const;
|
|
void toJson ( JsonWriter* ) const;
|
|
void toJsonSignature ( JsonWriter* ) const;
|
|
\endcode
|
|
*
|
|
* The JSON driver functions is splitted in two parts:
|
|
* - \c _toJson() must drive the scalar attributes.
|
|
* - \c _toJsonCollections() must drive the various collections
|
|
* or containers.
|
|
* This is to ensure that all the scalars attributes are put
|
|
* before the collections, event through inheritance.
|
|
*
|
|
* The additionnal \c toJsonSignature() method provide the
|
|
* signature for an Entity which is used by an occurrence.
|
|
* The signature of an occurrence is needed when we create
|
|
* a JSON for a Cell only. In that case we cannot directly save
|
|
* the transhierarchical informations, so we need a way to
|
|
* characterize the deep Entity (which is not part of the
|
|
* saved Cell). Most of the time, the signature is the scalar
|
|
* attributes of the occurrenced object, it is far from foolproof,
|
|
* but it will do for now.
|
|
*
|
|
*
|
|
* \section secJsonParser JSON Parser Support
|
|
*
|
|
* To enable JSON parsing support for an object, say Point,
|
|
* an associated \c JsonPoint class must be created. This
|
|
* class must be derived (directly or not) from JsonObject.
|
|
* It must implement one static functions and four methods,
|
|
* as shown below.
|
|
*
|
|
\code
|
|
class JsonPoint : public JsonObject {
|
|
public:
|
|
static void initialize ();
|
|
JsonPoint (unsigned long flags);
|
|
virtual string getTypeName() const;
|
|
virtual JsonPoint* clone (unsigned long flags) const;
|
|
virtual void toData (JsonStack&);
|
|
};
|
|
\endcode
|
|
*
|
|
* The \c initialize() static function must be present in
|
|
* concrete class only. It is used to register the Json
|
|
* object into the parser during the static initialization
|
|
* of the program.
|
|
*
|
|
\code
|
|
#include "hurricane/Initializer.h"
|
|
#include "hurricane/Point.h"
|
|
|
|
Initializer<JsonPoint> jsonPointInit ( 0 );
|
|
|
|
void JsonPoint::initialize ()
|
|
{ JsonTypes::registerType( new JsonPoint (JsonWriter::RegisterMode) ); }
|
|
|
|
\endcode
|
|
*
|
|
* The constructor has to declare requirements, attributes,
|
|
* and collections needed to build the DataBase object.
|
|
* Note the the requirements are not part of the objects
|
|
* but only needed to build it.
|
|
*
|
|
\code{.cpp}
|
|
JsonPoint::JsonPoint ( unsigned long flags )
|
|
: JsonObject(flags)
|
|
{
|
|
add( "_x", typeid(int64_t) );
|
|
add( "_y", typeid(int64_t) );
|
|
}
|
|
\endcode
|
|
*
|
|
* The \c getTypeName() virtual function must return the
|
|
* typename used for the \c "@typename" key in the JSON
|
|
* file. Most of the time it's the same name as the
|
|
* object itself, but not always.
|
|
*
|
|
\code{.cpp}
|
|
string JsonPoint::getTypeName () const
|
|
{ return "Point"; }
|
|
\endcode
|
|
*
|
|
* The \c clone() virtual function must return a brand new
|
|
* Json object of the same type. The datas of the orignal
|
|
* object \b must not be copied. The cloning is about the
|
|
* class type, not the contents.
|
|
*
|
|
\code
|
|
JsonPoint* JsonPoint::clone ( unsigned long flags ) const
|
|
{ return new JsonPoint ( flags ); }
|
|
\endcode
|
|
*
|
|
* The \c toData() virtual function actually gather the
|
|
* attributes to recreate the DataBase object. It needs
|
|
* the parser stack to pull the attributes and to push
|
|
* the created object.
|
|
*
|
|
\code{.cpp}
|
|
void JsonPoint::toData ( JsonStack& stack )
|
|
{
|
|
check( stack, "JsonPoint::toData" );
|
|
Point point ( DbU::fromDb(get<int64_t>(stack,"_x"))
|
|
, DbU::fromDb(get<int64_t>(stack,"_y")) );
|
|
update( stack, point );
|
|
}
|
|
\endcode
|
|
*
|
|
*
|
|
* \subsection secJsonArray JSON Array
|
|
*
|
|
* JSON array are not translated into containers of any kind.
|
|
* They are simply ignored (from the stack point of view).
|
|
* Objects in array comes from a great variety of containers
|
|
* including Hurricane::Collection, in almost all cases, their
|
|
* very constructors are responsibles for inserting the object
|
|
* in the relevant container/collection. So there is no need
|
|
* to build a mechanism to keep track of all the objects in an
|
|
* array through a temporary container.
|
|
*
|
|
* The corollary is that an object in an array must be able to
|
|
* extract the relevant context information from the stack.
|
|
* Say, if we are in an array of components, they must belong
|
|
* to a Net, which must be present in the stack with a key ".Net".
|
|
*
|
|
*
|
|
* \subsection secJsonStack Parser Stack
|
|
*
|
|
* While performing the parsing, the parser maintain a stack
|
|
* (JsonStack) containing:
|
|
* - The stack of attributes translateds, but not consumeds
|
|
* by the parser and the objects currently openeds (that is,
|
|
* which parsing is not completed). This stack contains POD
|
|
* or Hurricane objects (value or pointer).
|
|
* It is a vector of pair \c (key,value) where the \e key
|
|
* is either the attribute name (\c _boundingBox, \c _xMin,
|
|
* \c _masterCell, ...) or the class name (\c .Net, \c .Cell, ...).
|
|
* - The stack of JSON objects currently openeds, thoses objects
|
|
* are all derived classes of JsonObject.
|
|
* - A stack of currently opened DBo*. This stack is somewhat
|
|
* redundant with the first, but is needed because
|
|
* \c boost::any_cast<> is not able to perform dynamic conversions.
|
|
* You have to know the exact for the conversion to work.
|
|
* Here, everything is DBo*, so the problem do not arises.
|
|
*
|
|
*
|
|
* \subsection secJsonCycle JsonObject Life Cycle
|
|
*
|
|
\code{.json}
|
|
{ # JsonDummy() (1).
|
|
"_typename": "Net", # JsonNet() CTOR (2).
|
|
"_id": 14622,
|
|
"_name": "saccu(0)",
|
|
"_isGlobal": false,
|
|
"_isExternal": false,
|
|
"_isAutomatic": false,
|
|
"_type": "LOGICAL",
|
|
"_direction": "---- (UNDEFINED)",
|
|
"+aliases": [], # JsonNet::toData() (3).
|
|
"+componentSet": [
|
|
{
|
|
"@typename": "RoutingPad",
|
|
"_id": 27410,
|
|
"_bodyHook": "Contact::AnchorHook.46566",
|
|
"_occurrence": {
|
|
"@typename": "Occurrence",
|
|
"_path": "14720.14976",
|
|
"_entity": 3888
|
|
},
|
|
"+propertySet": []
|
|
},
|
|
{
|
|
"@typename": "RoutingPad",
|
|
"_id": 27409,
|
|
"_bodyHook": "Contact::AnchorHook.46574",
|
|
"_occurrence": {
|
|
"@typename": "Occurrence",
|
|
"_path": "14654.18564",
|
|
"_entity": 4529
|
|
},
|
|
"+propertySet": []
|
|
}
|
|
}
|
|
} # ~JsonNet() DTOR (4).
|
|
\endcode
|
|
*
|
|
* At \c (1) , before \c _typename is encountered, we know that a new
|
|
* object is about to be created, but do not know what is type will be.
|
|
* So we push on top of the stack a \c JsonDummy.
|
|
*
|
|
* At \c (2) , the \c _typename allows us to create the right kind of
|
|
* JsonObject, which will \e replace the \c JsonDummy on top of the
|
|
* stack.
|
|
*
|
|
* At \c (3) , a first non-POD attribute of JsonNet is encountered.
|
|
* This triggers the call to \c JsonObject::toData(), which creates
|
|
* the Hurricane object Net, and put it back on the attribute stack
|
|
* with the key \c ".Net" (because it is \e not an attribute).
|
|
*
|
|
* At \c (4) , the Json parser knows that the current JsonObject is
|
|
* finished, so it removes JsonNet from the stack and destroy it.
|
|
*
|
|
* So, if you need to perform specific post-processing that can only
|
|
* take place \c after the object and all it's sub-objects has been
|
|
* fully parsed, you may do it in the destructor of the JsonObject.
|
|
* For example, this technique is used to rebuild the rings of a Net.
|
|
*/
|
|
|
|
|
|
} // Hurricane namespace.
|