coriolis/hurricane/doc/hurricane/JsonSupport.dox

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.