home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / base / object.h < prev    next >
C/C++ Source or Header  |  1995-04-08  |  15KB  |  393 lines

  1.  
  2.  
  3. #ifndef _object_h_
  4. #define _object_h_
  5.  
  6.  
  7.  
  8.  
  9.  
  10. /*
  11.  *
  12.  *          Copyright (C) 1994, M. A. Sridhar
  13.  *  
  14.  *
  15.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  16.  *     to copy, modify or distribute this software  as you see fit,
  17.  *     and to use  it  for  any  purpose, provided   this copyright
  18.  *     notice and the following   disclaimer are included  with all
  19.  *     copies.
  20.  *
  21.  *                        DISCLAIMER
  22.  *
  23.  *     The author makes no warranties, either expressed or implied,
  24.  *     with respect  to  this  software, its  quality, performance,
  25.  *     merchantability, or fitness for any particular purpose. This
  26.  *     software is distributed  AS IS.  The  user of this  software
  27.  *     assumes all risks  as to its quality  and performance. In no
  28.  *     event shall the author be liable for any direct, indirect or
  29.  *     consequential damages, even if the  author has been  advised
  30.  *     as to the possibility of such damages.
  31.  *
  32.  */
  33.  
  34.  
  35.  
  36.  
  37. // The class Object serves as the root of the inheritance tree of
  38. // YACL. It provides for simple mechanisms for runtime type
  39. // identification (via class id's or class names), cloning (copying)
  40. // of objects (via the Clone() method), and dependent notification.
  41. //
  42. // Every object instance maintains two sets of  dependents, who are to be
  43. // notified just before and just  after the  object  is modified. (It  is
  44. // upto the individual  object  to decide  exactly what its  modification
  45. // means;    for  example,  all  base  objects   regard "modification" as
  46. // alteration of their   value in some way.)  An   object A can  register
  47. // itself  as  a  (post-modification)  dependent  on   object B  via  the
  48. // AddDependent() call on   B,  which  also  specifies  a  method on   A.
  49. // Subsequently,  whenever B invokes  Notify()  on itself, the  specified
  50. // method    on A  is   called, with  B  and  the    notification code as
  51. // parameters.
  52. // 
  53. // Similarly,  object  A  can    register itself  as   a pre-modification
  54. // dependent of object B via the call to AddPreChangeDependent(). If B is
  55. // any   base  object that   has    a nonempty  set  of  pre-modification
  56. // dependents, then B consults all  of these dependents before  modifying
  57. // itself, and remains unaltered if any of the dependent bindings returns
  58. // a FALSE value.
  59. // 
  60. // The  sets of dependents   are implemented  via  a  single  pointer  as
  61. // instance variable, to minimize  overhead on  objects  that do not  use
  62. // dependents. These sets are {\it not\/} copied when the object is copied.
  63.  
  64.  
  65.  
  66.  
  67. #ifdef __GNUC__
  68. #pragma interface
  69. #endif
  70.  
  71. #include "base/defs.h"
  72. #include "base/classid.h"
  73. #include "base/error.h"
  74.  
  75. class CL_EXPORT  CL_Object;
  76. class CL_EXPORT  CL_AbstractBinding;
  77. class CL_EXPORT  CL_ByteArray;
  78. class CL_EXPORT  CL_ByteString;
  79. class CL_EXPORT  CL_String;
  80. class CL_EXPORT  CL_Stream;
  81. class CL_EXPORT  CL_Integer;
  82. template <class K, class V>
  83. class CL_EXPORT  CL_Map;
  84.  
  85.  
  86. // The iostream classes are declared this way, rather than including
  87. // iostream.h, to minimize preprocessing time:
  88. class  __FAR istream;
  89. class  __FAR ostream;
  90.  
  91.  
  92. typedef CL_Object*  CL_ObjectPtr;
  93. typedef CL_Object*  (*CL_Creator) (); // For persistence support
  94.  
  95. typedef long        CL_ClassId; // This class id representation may be
  96.                                 // changed in future.
  97.  
  98. struct CL_DependStruct;
  99.  
  100. class CL_EXPORT CL_Object {
  101.  
  102. public:
  103.     
  104.     CL_Object();
  105.     // Default constructor.
  106.  
  107.     CL_Object (const CL_Object&);
  108.     // Copy constructor.
  109.     
  110.     virtual ~CL_Object() = 0;
  111.     // Destructor, declared virtual, so the destructors of all derived
  112.     // classes are virtual.
  113.  
  114.  
  115.     // ------------------ Object identification --------------------------
  116.  
  117.     virtual const char* ClassName() const { return "CL_Object";};
  118.     // Return the class name of this object.
  119.     
  120.     virtual CL_ClassId ClassId () const {return _CL_Object_CLASSID;};
  121.     // Return the class id of this object.
  122.  
  123.     virtual bool IsA (const CL_Object& obj) const
  124.         {return ClassId() == obj.ClassId();};
  125.     // Return TRUE if our this object's class is the same as, or derived
  126.     // from, that of {\tt obj}. The current implementation only checks
  127.     // equality of ClassId values, so it really doesn't take care of derived
  128.     // classes.
  129.  
  130.     bool CheckClassType (const CL_Object& o, const char* msg) const;
  131.     // Check that {\tt o} has the same type as this object (via {\tt
  132.     // IsA}), and issue an error message containing {\tt msg} otherwise.
  133.     // Return  the value returned by {\tt IsA}.
  134.     
  135.     // ------------------- Copying -----------------------------------
  136.  
  137.     virtual CL_Object* Clone () const;
  138.     // Return a copy of ourselves. Whether this is a shallow or deep
  139.     // copy depends on the derived class. All primitive (i.e.
  140.     // non-container) subclasses must return a deep copy. The caller
  141.     // must destroy the returned object. The default implementation issues a
  142.     // "Not implemented" error message.
  143.  
  144.     
  145.     // -------------------- Comparison operators -------------------
  146.  
  147.     
  148.     virtual bool operator<  (const CL_Object& obj) const;
  149.     // This and operator {\tt ==} constitute the two basic comparison
  150.     // operators.
  151.     // This operator must be implemented by every derived class that can
  152.     // be thought of as defining an "orderable" type. The default
  153.     // implementation uses addresses for comparison; therefore, if the
  154.     // derived class doesn't care about ordering, this operator need not
  155.     // be overridden.
  156.     
  157.     virtual bool operator== (const CL_Object& obj) const;
  158.     // The default implementation checks for equality of addresses.
  159.  
  160.  
  161.     virtual bool operator<= (const CL_Object& obj) const
  162.         { return (*this == obj || *this < obj);};
  163.     // This and the other three relational operators ({\tt >}, {\tt >=}
  164.     // and {\tt !=}) have
  165.     // default implementations that invoke the operators {\tt ==} and {\tt
  166.     // <}. Thus a derived class that defines an "orderable" object need
  167.     // only override the {\tt ==} and {\tt <} operators.
  168.  
  169.     virtual bool operator>  (const CL_Object& obj) const
  170.         {return (! (*this <= obj));} ;
  171.  
  172.     virtual bool operator>= (const CL_Object& obj) const
  173.         {return (! (*this < obj));};
  174.  
  175.     virtual bool operator!= (const CL_Object& obj) const
  176.         {return (! (*this == obj));};
  177.  
  178.     virtual short Compare (const CL_Object& obj) const
  179.         { return (*this == obj) ? 0 : ((*this < obj) ? -1 : 1);};
  180.     // This method defines "strcmp"-style comparison. The default
  181.     // implementation invokes (only) the operators {\tt ==} and {\tt <} on this
  182.     // object, in that order. Therefore, if a derived class chooses to
  183.     // override only the < operator, then == is still used on addresses.
  184.  
  185.     
  186.     enum ComparisonOperator {OP_EQUAL = 0, OP_LESSTHAN, OP_GTRTHAN,
  187.                              OP_LESSEQ, OP_GTREQ, OP_PREFIX,
  188.                              OP_CONTAINS, OP_NOTEQUAL};
  189.     virtual bool CompareWith (const CL_Object& obj,
  190.                               ComparisonOperator op) const;
  191.     // ``Indirect'' comparison, given a comparison operator:
  192.     // compare ourselves with the given object (after ensuring
  193.     // correct class id), and return a boolean value according to whether
  194.     // the required relationship holds between us and the given
  195.     // object. E.g., given objects p and q, {\small\tt p.CompareWith (q,
  196.     // OP_LESSTHAN)} yields TRUE if p is less than q. For the PREFIX and
  197.     // CONTAINS operators on non-string objects, the {\small\tt
  198.     // AsString()} method 
  199.     // is applied to both operands before doing the comparison.
  200.  
  201.     virtual bool CompareWith (const CL_String& obj,
  202.                               ComparisonOperator op) const;
  203.     // This is similar to Compare, except the given object is a string, so we
  204.     // convert ourselves into a string (via the {\small\tt AsString()}
  205.     // method on this object) before comparing.
  206.     
  207.     // ---------------------- Assignment ----------------------------
  208.  
  209.     virtual void operator= (const CL_Object&);
  210.     // The default implementation issues a "Not implemented" error message.
  211.  
  212.     
  213.     // ------------------- Passive representations of object -----------
  214.  
  215.     // ----- Representation as a printable string ---
  216.     
  217.     virtual CL_String AsString () const; 
  218.     // Return a representation of this object in string
  219.     // form. The default implementation issues a "Not implemented"
  220.     // warning message via the {\small\tt NotImplemented} method, and
  221.     // returns the null string; this method must be overridden by derived
  222.     // classes.
  223.  
  224.  
  225.     virtual void IntoStream (ostream& strm) const;
  226.     // Write this object's string representation onto the given {\small\tt
  227.     // ostream}.  The default implementation invokes {\small\tt
  228.     // AsString()} and writes the result to the stream; this method may be
  229.     // overridden by derived classes if necessary.
  230.  
  231.  
  232.     virtual void FromStream (istream& stream);
  233.     // Read this object's value from its string representation in the
  234.     // given {\small\tt istream}.  The default implementation does
  235.     // nothing; this method must be overridden by derived classes.
  236.  
  237.  
  238.     // ----- Saving and restoration in binary form ----
  239.     
  240.     virtual long StorableFormWidth () const {return 0;};
  241.     // Return the number of bytes in the binary storable representation
  242.     // of this object. The default implementation returns 0.
  243.  
  244.     virtual bool ReadFrom (const CL_Stream&);
  245.     // Read and reconstruct ourselves from the binary representation in
  246.     // the given stream. Return TRUE on success, FALSE if failed for any
  247.     // reason, including when a pre-change dependent disallows the change.
  248.     // The default implementation issues a "Not implemented" message.
  249.  
  250.     virtual bool WriteTo  (CL_Stream&) const;
  251.     // Write the passive binary representation of this object into the
  252.     // given stream. Return TRUE if successful, FALSE otherwise. The
  253.     // default implementation issues a "Not implemented" error message.
  254.  
  255.     // ------------------ Dependents and notification -------------------
  256.  
  257.  
  258.     // ----- Post-change dependency methods:
  259.     
  260.     void Notify ();
  261.     // Notify all our dependents by calling the associated methods,
  262.     // with ourselves as parameter.
  263.     
  264.     void AddDependent (const CL_AbstractBinding& binding, long code);
  265.     // Add a dependent to this object's dependent list. The given
  266.     // method will be called on the given object when Notify() is
  267.     // called. A binding can only appear once in our dependent set; so we
  268.     // cannot add the same binding with different codes as dependents.
  269.     
  270.     void RemoveDependent (const CL_AbstractBinding& binding);
  271.     // Remove a binding from our dependent list.
  272.     
  273.     bool HasDependent (const CL_AbstractBinding& b) const;
  274.     // Is the given object dependent on us?
  275.  
  276.     long& PreChangeCode (const CL_AbstractBinding& b) const;
  277.     // Return a reference to the notification code associated with the
  278.     // given binding, if the latter is in our pre-change dependency set.
  279.     // Return a reference to a zero-valued integer otherwise. The return
  280.     // value may be modified by the caller of this method.
  281.  
  282.  
  283.     // ----- Pre-change dependency methods:
  284.  
  285.     bool PrepareToChange ();
  286.     // Ask all our pre-change dependents whether it's ok to change our
  287.     // value; return FALSE if any of them returns FALSE, and TRUE if
  288.     // all of them return TRUE.
  289.  
  290.     void AddPreChangeDependent (const CL_AbstractBinding& binding, long code);
  291.     // Add a pre-change dependent.
  292.     
  293.     void RemovePreChangeDependent (const CL_AbstractBinding& binding);
  294.     // Remove a binding from our dependent list
  295.     
  296.     bool HasPreChangeDependent (const CL_AbstractBinding& b) const;
  297.     // Is the given object dependent on us?
  298.  
  299.     long& PostChangeCode (const CL_AbstractBinding& b) const;
  300.     // Return a reference to the notification code associated with the
  301.     // given binding, if the latter is in our post-change dependency set.
  302.     // Return a reference to a zero-valued integer otherwise. The return
  303.     // value may be modified by the caller of this method.
  304.  
  305.     // ------------------- End public protocol ----------------------------
  306.  
  307. protected:
  308.     void NotImplemented (const char* method_name) const;
  309.  
  310.     bool ReadClassId (const CL_Stream&) const;
  311.  
  312.     static CL_Map<long,long>& _ClassIdMap;
  313.     
  314. private:
  315.     CL_DependStruct* _dependSet;
  316. };
  317.  
  318.  
  319. class CL_EXPORT CL_ClassIdEntryMaker: public CL_Object {
  320.  
  321. public:
  322.     CL_ClassIdEntryMaker (CL_ClassId id, CL_Creator func);
  323.  
  324.     ~CL_ClassIdEntryMaker ();
  325.  
  326. };
  327.  
  328.  
  329. #define CL_DEFINE_CLASS(cls, cls_id)                            \
  330.      CL_Object* CL_Creator__ ## cls ()                          \
  331.      {                                                          \
  332.          return new cls;                                        \
  333.      }                                                          \
  334.      static CL_ClassIdEntryMaker CL_AddEntry__ ## cls ## __instance \
  335.      (cls_id, CL_Creator__ ## cls)
  336.  
  337.  
  338.  
  339. // --------------------------- Operator definitions --------------
  340.  
  341. istream& operator>> (istream& s, CL_Object& o); // Uses the FromStream
  342.                                                 // method
  343.  
  344. ostream& operator<< (ostream& s, const CL_Object& o); // Uses the IntoStream
  345.                                                       // method
  346.  
  347.  
  348. // -------------------------- Inline methods ----------------------
  349.  
  350. inline CL_Object::CL_Object()
  351. {
  352.     _dependSet = NULL;
  353. }
  354.  
  355.  
  356. inline CL_Object::CL_Object (const CL_Object&)
  357. {
  358.     _dependSet = NULL;
  359. }
  360.  
  361. inline bool CL_Object::CheckClassType (const CL_Object& o, const char*
  362.                                        msg) const
  363. {
  364.     register bool b = IsA (o);
  365.     if (!b)
  366.         CL_Error::Warning ("%s: Invalid class '%s'", msg, o.ClassName());
  367.     return b;
  368. }
  369.  
  370. inline void CL_Object::NotImplemented (const char* method_name) const
  371. {
  372.     CL_Error::Warning ("Class '%s' does not implement method '%s'\n",
  373.                        ClassName(), method_name);
  374. }
  375.     
  376. inline CL_Object* CL_Object::Clone () const
  377. {
  378.     NotImplemented ("Clone"); return NULL;
  379. }
  380.  
  381.  
  382.  
  383. inline void CL_Object::operator= (const CL_Object&)
  384. {
  385.     NotImplemented ("op= (const CL_Object&)");
  386. }
  387.  
  388. inline void CL_Object::FromStream (istream&)
  389. {
  390. }
  391.  
  392. #endif
  393.