📄 cdlcore.hxx
字号:
// bidirectional: if a "requires" property in option A references// option B then it would be useful to have a link back to A from B;// that way, if the value of B changes it is a lot easier to keep// things up to date.//// Terminology: the entity which contains the reference, e.g. a// "requires" property, is the source. The relevant property is the// "source property". The entity pointed at is the destination.//// Unfortunately there may be connections between CDL entities outside// the tree hierarchy. In particular any property can contain one or// more references to packages, components, options, wizards, or// whatever. Often these references will be to options etc. within the// same package, but some references will go to other packages. There// may even be references to other configurations: for example a board// may contain both an ordinary processor and a DSP; these two need// their own configurations; however a package running on the DSP may// need to interact with a package running on the processor, and vice// versa.//// Also, a reference may occur inside an object that is not in the// hierarchy. For example CDL expressions may get evaluated inside Tcl// code rather than as part of a property. Such expressions may still// contain references to entities in the current configuration.//// References may not be resolved. When reading in a CDL script there// may be forward references. A reference may involve another package// that has not yet been loaded, which is a conflict.//// Using simple pointers to store these connections is a bad idea. It// makes it a lot harder to figure out what is connected to what, and// it introduces horrible consistency problems when packages get// loaded and unloaded. Instead libCDL provides a CdlReference class.// Whenever a CdlProperty contains a reference to some other CDL// entity there should be a CdlReference object corresponding to this.// The reverse direction is handled via a CdlReferrer object.//// A CdlReference object can be either bound or unbound. By default it// is unbound, containing only a string. It can then be bound via a// member function, examined, and unbound again as required. Creating// a binding automatically creates a CdlReferrer entry in the target// object, thus avoiding any risk of inconsistencies.//// The CdlReference class should not be used outside the hierarchy,// since every bound reference must have a referrer object pointing// back, and this link back can only be valid within the hierarchy.// Temporary CdlReference objects are useful during the construction// of properties.//// It is possible that a given property (e.g. a complicated "requires"// expression) has multiple references to another entity. Each of// these involves a separate CdlReference/CdlReferrer pair.// ----------------------------------------------------------------------------// The actual CdlReference class.class CdlReference { friend class CdlTest; // CdlReferrer must be a friend so that when a package gets unloaded // it can clean up all references to it. friend class CdlReferrer; public: // The default constructor should not normally be used, instead // a string should be supplied. However there are vectors of // reference objects... CdlReference(); // The main constructor supplies the name of the referenced // entity. The resulting object will be unbound. CdlReference(const std::string); // The copy constructor is legal for unbound objects only. CdlReference(const CdlReference&); // The assignment operator is needed for STL operations. // Again it only makes sense of unbound objects. CdlReference& operator=(const CdlReference&); // The destructor is only valid for unbound objects. All references // should be unbound before an entity can be destroyed. ~CdlReference(); // Access the various fields. void set_destination_name(const std::string); const std::string& get_destination_name() const; CdlNode get_destination() const; // Binding a reference. Obviously this can only be used when the // reference is still unbound. When doing the binding it is // necessary to know: // (1) the object containing the reference. // (2) the specific property that contains the reference. // (3) the object being referred to. // Binding a reference results in a new referrer entry in the // destination. void bind(CdlNode, CdlProperty, CdlNode); // Unbinding a reference. Typically this only happens when the // destination is unloaded. The arguments provide the source and // the source property. void unbind(CdlNode, CdlProperty); // This is used by the ASSERT_CLASS() and ASSERT_THIS() macros. bool check_this(cyg_assert_class_zeal cyg_quick) const; CYGDBG_DECLARE_MEMLEAK_COUNTER(); protected: private: // The data fields. The name is usually filled in by the // constructor. The destination defaults to zero for an unbound // object and gets filled in by the bind() operation. std::string dest_name; CdlNode dest; enum { CdlReference_Invalid = 0, CdlReference_Magic = 0x3f908608 } cdlreference_cookie;};// ----------------------------------------------------------------------------// The CdlNode class (and hence just about everything) contains a// vector of CdlReferrer objects. This keeps track of all entities// that refer to this one, so if the value associated with this// changes it is possible to work out the impact of this on all// entities that rely on this value.//// Arguably this should work in terms of CdlValuable objects rather// than CdlNode objects. However it is convenient to use references// for the connection between e.g. an option and a dialog, where// there is no value involved. The reverse connection is of little// use in this circumstance.//// CdlReferrer objects are rarely accessed directly. Instead they will// be filled in during a CdlReference::bind() operation and erased// during a CdlReference::unbind() operation. The only operations that// should be public allow access to the contained data.class CdlReferrer { friend class CdlTest; // CdlReference::bind() and unbind() have direct access to the // members, since these two functions are really responsible for // creating and destroying referrer objects. friend class CdlReference; public: // The default constructor, copy constructor and assignment // operator are all public to avoid problems with having vectors // of referrer objects. Similarly the destructor is public. // In practice updates actually happen as a consequence of // CdlReference::bind() and CdlReference::unbind(). CdlReferrer(); CdlReferrer(const CdlReferrer&); CdlReferrer& operator=(const CdlReferrer&); ~CdlReferrer(); CdlNode get_source() const; CdlProperty get_source_property() const; void update(CdlTransaction, CdlNode, CdlUpdate); bool check_this(cyg_assert_class_zeal=cyg_quick) const; CYGDBG_DECLARE_MEMLEAK_COUNTER(); private: CdlNode source; CdlProperty source_property; enum { CdlReferrer_Invalid = 0, CdlReferrer_Magic = 0x70e1fc37 } cdlreferrer_cookie;};//}}}//{{{ Value and Expression classes //{{{ CdlEvalContext // ----------------------------------------------------------------------------// Expression evaluation always happens within a certain context.// This may involve a transaction. Usually it involves a node and// a property within that node, although it is possible to evaluate// expressions from inside Tcl code.//// To avoid passing too many arguments around the various// evaluation-related routines, a utility class is provided.class CdlEvalContext { friend class CdlTest; public: CdlTransaction transaction; CdlNode node; CdlProperty property; CdlToplevel toplevel; CdlEvalContext(CdlTransaction, CdlNode, CdlProperty, CdlToplevel = 0); ~CdlEvalContext(); bool check_this(cyg_assert_class_zeal = cyg_quick) const; CYGDBG_DECLARE_MEMLEAK_COUNTER(); protected: private: // Illegal operation, the three fields must always be supplied, // although they may be zero. CdlEvalContext(); enum { CdlEvalContext_Invalid = 0, CdlEvalContext_Magic = 0x03434be9 } cdlevalcontext_cookie; };//}}}//{{{ CdlSimpleValue // ----------------------------------------------------------------------------// Expression evaluation happens in terms of CdlSimpleValue objects.// In CDL all values are strings, but for the purposes of arithmetic// these strings sometimes have to be interpreted as integers or as// double precision numbers. Sometimes there is a choice, for example// the equality operator == can mean numerical or string comparison.// The basic rules that get applied are://// 1) if the current value has an integer representation then// use this by preference. This means that an expression// of the form (CYGNUM_XXX != 0x100) will do a integer// comparison if possible.//// 2) otherwise if the current value can be interpreted as a// double precision number, use that representation.// All integers can be interpreted as doubles (at the risk// of some loss of precision), so the representation as// a double should only be used if the integer representation// is inappropriate.//// 3) otherwise interpret the value as a string.//// The default value is 0.class CdlSimpleValue { friend class CdlTest; public: CdlSimpleValue(); CdlSimpleValue(std::string); CdlSimpleValue(cdl_int); CdlSimpleValue(double); CdlSimpleValue(const CdlSimpleValue&); CdlSimpleValue(bool); ~CdlSimpleValue(); CdlSimpleValue& operator=(const CdlSimpleValue&); CdlSimpleValue& operator=(std::string); CdlSimpleValue& operator=(cdl_int); CdlSimpleValue& operator=(double); CdlSimpleValue& operator=(bool); bool operator==(const CdlSimpleValue&) const; bool operator!=(const CdlSimpleValue&) const; bool operator==(std::string arg) const { CdlSimpleValue val(arg); return *this == val; } bool operator==(cdl_int arg) const { CdlSimpleValue val(arg); return *this == val; } bool operator==(double arg) const { CdlSimpleValue val(arg); return *this == val; } bool operator!=(std::string arg) const { CdlSimpleValue val(arg); return *this != val; } bool operator!=(cdl_int arg) const { CdlSimpleValue val(arg); return *this != val; } bool operator!=(double arg) const { CdlSimpleValue val(arg); return *this != val; } void set_value(std::s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -