// -*- 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 design blob. * * 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 void jsonWrite ( JsonWriter* w, const C* object ); template void jsonWrite ( JsonWriter* w, const std::string& key, C* object ); template 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 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(stack,"_x")) , DbU::fromDb(get(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.