// -*- C++ -*- namespace Hurricane { /*! \class Property * \brief Property description (\b API) * * \section secPropertyIntro Introduction * * Properties can be attached to the data base objects. Those * properties must have a name in order to access them * unambiguously. Of course only one property of a given name * can be attached to an object. * * In a first step we define two great categories of properties * : the private properties which can be attached to only one * object and the shared properties which can be attached to a * large number of objects. * * We will detail separately their respective behaviour, but we * ensure that the management of each of those two property * categories is absolutely secure. That is, on one side you can * destroy explicitely a property (and the objects will be * notified) and on the other side the properties will be * automatically destroyed when no more object reference them. * * \remark By overloading some messages, as we will see later, it is * possible to set up different behaviours (like avoid the * automatic delete). * * * \section secPropertyTheQuarks The Quarks * * As we shall see, the occurences are very simple objects which * are used to designate some entity of the virtually unfolded * hierarchy. Indeed, those occurences, which are built and * deleted very quickly, are very volatile objects to which * obvioulsy we can't attach properties directly. * * But the interest of occurences is precisely to be able to * attach them properties. In order to be able to do that, * properties must be stored in a secure place where we could * find them when needed. The quarks are here for that purpose : * they are subtypes of data base object and therefore can store * the properties attached to occurences. * * \important only one quark is attached to all occurences which refer the * same entity of the virtually unfolded hierarchy. This means * that a property placed on an occurence can be read by any * other occurence which refers the same entity of the virtually * unfolded hierarchy. * * \remark Those quarks are also volatile objects because their only * reason to exist is that at least one property is attached to * them. * * * \section secPropertyHowThatWorks How that works * * We will detail the way properties are managed by analysing * more precisely what happens at the level of property access * functions both for data base objects and for occurences. * * * Accessing a property by its name \code Property* DBo::getProperty(const Name& name) const; \endcode * This member function returns the property of name \c \ * if there is one attached to the object, else NULL. \code Property* Occurrence::getProperty(const Name& name) const; \endcode * This function searches in a first time the quark representing * the occurence. * * If the quark doesn't exist, this means there is no property * attached to that occurence, then the function returns NULL. * * If the quark does exist, the function returns the property of * name \c \ attached to the quark, if any, by calling * the previous function (because quarks are data base objects). * * * Accessing the set of all properties \code Properties DBo::getProperties() const; \endcode * Return the collection of properties attached to the object (possibly * empty). \code Properties Occurrence::getProperties() const; \endcode * This function searches in a first time the quark representing * the occurence. * * If the quark doesn't exist, this means there is no property * attached to that occurence, then the function returns an * empty property collection. * * If the quark does exist, the function returns the property * collection attached to the quark, by calling the previous * function (the returned collection is inevitably non empty, * else the quark would not exist). * * * Does the object have properties ? \code bool DBo::hasProperty() const; \endcode * Return \true if the object owns at least a property, else \false. \code bool Occurrence::hasProperty() const; \endcode * This function searches the quark representing the occurence. * * If the quark does exist it means there is at least a property * assigned to it and the function returns \true, else it * returns \false. * * * Adding a property : things becomes a little harder \code void DBo::put(Property* property); \endcode * Adds the property \c \ to the set of properties of * the object. \code void Occurrence::put(Property* property); \endcode * This function searches the quark representing the occurence. * * If the quark doesn't exist it is automatically created in * order to attach this first property. * * once the quark has been got or created, we can add the * property with the previous function. * * Two important things might happen then : The property is * already owned by an other object (may be a quark) and that * property is not a shared one and/or the object owns * already a property with the same name. * * Therefore it may happen, within this step, that adding a * property to an object leads to the deletion of an other * property on that object (name unicity) or on an other * object (unicity of owner for a private property). * * Which behaviour should we have in such conditions ? Shall we * destroy the property which has been detached ? There is no * unique behaviour which matches all needs. In order to solve * this problem the properties must answer to two specific * messages which are : onCapturedBy(DBo* dbo) when the * property is attached to an object and onReleasedBy(DBo* * dbo) when it is detached from the object. It is within * that last message that the decision about the future of the * property must be taken. * * \remark We will detail below those messages for both private and * shared properties. * * * Removing a property \code void DBo::remove(Property* property); \endcode * Removes the property \c \ from the set of * properties of the object. \code void Occurrence::remove(Property* property); \endcode * The function searches for the quark associated to the * occurence. * * If the quark doesn't exist, there is nothing to do, the * occurence has no properties. * * Else the property is removed from the set of quark properties * by calling the previous function. Furthermore if this removed * property is the last one, the quark is automatically deleted. * * \important The message onReleasedBy is called upon as explained * above. This call will decide of the future of the removed * property. * * * Clearing all properties \code void DBo::clearProperties(); \endcode * Removes all properties attached to the object. \code void Occurrence::clearProperties(); \endcode * First searches for the quark associated to the occurence. * * If the quark exist it is simply destroyed after removing all * its private properties and detaching it from all its shared * properties (wich may lead to their removal). Without quark * the occurence looses all its properties. * * \important Here again the message onReleasedBy is called upon for * each removed property. * * * \section secPropertyCreationProcess Creation process * * The creation process is similar to the data base objects * creation one. Therefore a property must be created by the * special function Create and not by the usual new * (which is not available). * * * \section secPropertyDeletionProcess Deletion process * * Hurricane::Property::destroy * * * \section secPropertyNaming Naming Conventions * * Properties being named and the their management being based * on that name, it could occur conflicts between Hurricane * which use some properties and the different tools which will * be plugged above, or between different tools themselves. * * In order to avoid that you must take some precautions in the * choice of the property names. * * So Hurricane uses properties prefixed by the string * "Hurricane::",like for instance "Hurricane::Selector" for the * property of type Selector. * * So I suggest that different tools use a * similar namming strategy which would keep confident all the * community of hurricaners * * \remark Using names like "ZenTek::TimingNode" for the TimingNode type * property managed by tools from the ZenTek society decreases * name conflicts, unless with other tools from the same * society. A property name * "SocietyName::ToolName::PropertyName" would be more secure. * * Furthermore, if the community adopts this convention it will * be possible to simplify some parts of the code by avoiding * for example calls to the macro is_a to check that the * collected property is of the expected type, as shown in the * following example : \code Property* property = occurence.getProperty("Hurricane::Selector"); if (property && is_a(property)) { Selector* selector = (Selector*)property; // ... } \endcode * Which could become : \code Selector* selector = (Selector*)occurence.getProperty("Hurricane::Selector"); if (selector) { // ... } \endcode * * * \section secPropertyRemarks Remarks * * The name of properties being of type Name and not of type * string, the comparison between two names operates on their * pointers and not on their character strings. The length of * the name doesn't affect the comparison performance. * * on the other hand, the time to create a property name depends * obviously of its length and of the number of names (which * fortunately are managed by efficient map containers). * * Therefore in order to avoid building names at each property * access, you must provide a specific function which returns a * Name object allocated once and once only. * * As a matter of fact if you write, like in the previous * example : \code Property* property = occurence.getProperty("Hurricane::Selector"); \endcode * Each time the name is built and this will degrade * performance. * * on the other hand if the following static member function is * provided : \code const Name& Selector::getPropertyName () { static Name NAME = "Hurricane::Selector"; return NAME; } \endcode * You could write later : \code Property* property = occurence.getProperty(Selector::getPropertyName()); \endcode * This approach is much more efficient and presents an other * interest : you don't need to know the name of the property * being handled. This allows to change property names without * affecting existing code. * * Therefore I propose, for every new * instanciable property (whose name depends of the property * type), that a static member function be systematically * provided. * * Furthermore, both StandardPrivateProperty and * StandardSharedProperty have, as we shall see later, an * attribute giving their name. Here again, for accessing the * propety, a name must be created. * * So I propose also that a global * function (which can't be a static member function) be defined * for each new property name. * * That way, by defining (i.e. for the property ObjectId) the * function : \code const Name& getObjectIdPropertyName () { static Name NAME = "Hurricane::ObjectId"; return NAME; } \endcode * You can write later : \code Property* property = occurence.getProperty(getObjectIdPropertyName()); \endcode */ /*! \function Name Property::getName() const; * \Return the name of the property : this method must absolutely be * overloaded for all new property classes, because the property * name is not a "wired in" attribute. A property being a real * object, this name derives naturally from the property type * name (so don't loose room uselessly to store it in a record * slot). */ /*! \function void Property::onCapturedBy(DBo* dbo); * This message is called upon when the property is added to the * properties of \c \. * * By default this function does nothing particular, but it must * be overloaded for all property sub-classes. We will detail * later the reaction to this message as taken by the private * and shared property classes. * * \remark This message being already overloaded for private and shared * property classes there is no need to overload it again when * specializing any of those two classes. */ /*! \function void Property::onReleasedBy(DBo* dbo); * This message is called upon when the property is removed from * the \c \ properties. * * \important The argument \c \ is not (or no more) necessarily the * owner of the property which receives the message. The * processing to be done in reaction to this message often * depends on this observation. We will better understand this * subtlety when studying private properties. * * \remark This message being already overloaded for private and shared * property classes there is no need to overload it again when * specializing any of those two classes. */ //! \name Property Collection // \{ /*! \typedef Properties * Generic collection representing a set of properties. */ /*! \typedef PropertyLocator * Generic locator for visiting a property collection. */ /*! \typedef PropertyFilter * Filter to selecting a subset of properties matching some * criteria. */ /*! \def forEach(Property*, iproperty, properties) * Macro for visiting all properties of a property collection. \code Occurrence occurence = ...; // we get an occurence forEach(Property*, iproperty, occurence.getProperties()) { cerr << *iproperty << endl; } \endcode */ // \} /*! \function void Property::destroy(); * Like the data base objects, properties can be destroyed by * calling upon this function and not the standard C++ * destructor (which is not available). */ }