00001 #ifndef IfdKey_HH 00002 #define IfdKey_HH 00003 //-------------------------------------------------------------------------- 00004 // File and Version Information: 00005 // $Id: IfdKey.h,v 1.1.1.1 2005/04/21 01:18:05 zhangy Exp $ 00006 // 00007 // Description: 00008 // IfdKey is a Key, i.e., something that knows operator== and, 00009 // maybe someday, operator<. Subclasses, like IfdIntKey and IfdStrKey 00010 // allow keys based on integer and string values. Another derivative, 00011 // IfdTypeKey<T> serves as mapping between C++ static classes and 00012 // Keys. Finally, IfdKey wroks with its derivative, IfdCompositeKey, 00013 // to form a composite pattern that allows lists, trees, etc. of 00014 // keys to be formed and yet have an op== defined on it. 00015 // 00016 // Usage: Keys do not know op=, i.e., assignemnt, and I have supressed 00017 // the copy ctor. You should pass them by reference or poiner. There 00018 // is a clone() method, so a consumer can effective copy a key. Note 00019 // that this means that the caller retains ownership of the key, and 00020 // the "consumer" that takes a copy *owns* the copy. 00021 // 00022 // Author List: 00023 // Ed Frank University of Pennsylvania 00024 // 00025 // History: 00026 // Ed Frank 17 Nov 96 Creation of first version 00027 // 00028 // Bugs: 00029 // 00030 //------------------------------------------------------------------------ 00031 00032 // 00033 // Reading IntIfdKey.hh after this is helpful. Then tackle CompositeIfdKey.hh 00034 // 00035 00036 00037 #include <assert.h> 00038 #include <stdlib.h> 00039 class HepString; 00040 #if !(defined(__GNUC__) && (__GNUC__ < 3) && (__GNUC_MINOR__ < 95)) // BABAR_IOSTREAMS_MIGRATION 00041 #include <iosfwd> 00042 #else // BABAR_IOSTREAMS_MIGRATION 00043 class ostream; 00044 #endif // BABAR_IOSTREAMS_MIGRATION 00045 class IfdDictKey; 00046 //template<class T> class TypeKey; 00047 00048 class IfdKey { 00049 public: 00050 virtual ~IfdKey(); 00051 00052 virtual int operator==( const IfdKey & ) const = 0; 00053 inline int operator!=( const IfdKey &k ) const; 00054 00055 00056 virtual void add( const IfdKey& ); 00057 00058 inline int cardinality(void) const; 00059 // For Composite keys, == # of added elements. For Non-Composites, == 0; 00060 00061 #if !(defined(__GNUC__) && (__GNUC__ < 3) && (__GNUC_MINOR__ < 95)) // BABAR_IOSTREAMS_MIGRATION 00062 virtual void print( std::ostream &o ) const = 0; 00063 #else // BABAR_IOSTREAMS_MIGRATION 00064 virtual void print( ostream &o ) const = 0; 00065 #endif // BABAR_IOSTREAMS_MIGRATION 00066 #if !(defined(__GNUC__) && (__GNUC__ < 3) && (__GNUC_MINOR__ < 95)) // BABAR_IOSTREAMS_MIGRATION 00067 friend std::ostream& operator<<( std::ostream& o, const IfdKey & k ); 00068 #else // BABAR_IOSTREAMS_MIGRATION 00069 friend ostream& operator<<( ostream& o, const IfdKey & k ); 00070 #endif // BABAR_IOSTREAMS_MIGRATION 00071 00072 virtual IfdKey* clone( void ) const = 0; 00073 // Clone makes an exact copy of an object. It is crucial that 00074 // derivatives implement this in a way that places the created 00075 // object on the heap. 00076 00077 virtual unsigned int hash( void ) const 00078 { return _hashVal;} 00079 00080 unsigned int _hashVal; //$$ public (ick) for now. clean later. 00081 00082 static unsigned int nHashBuckets( void ) 00083 { return _nHashBuckets; } 00084 00085 protected: 00086 enum { _nHashBuckets = 1031 }; // .33 msec/ev, not opt 00087 00088 enum keyKind { intKey, strKey, compositeKey, 00089 typeKey, odfTypeKey }; 00090 00091 IfdKey( keyKind kind ); 00092 // IfdKey is a pure interface. Prevent creation of them. Only 00093 // derivatives can be created and this ctor requires them to 00094 // define their keykind at ctor time. This could have been 00095 // a virtual getKeyKind, but that affected performance. See below. 00096 00097 00098 inline IfdKey::keyKind getKeyKind( void ) const { return _myKeyKind; } 00099 // IfdKeys are things that understand operator==. We have made 00100 // this machinery rather than a simple overloaded global op== 00101 // because we wanted CompositeKey's, i.e., IfdKeys with subfields. 00102 // The enum above allows the subfields to be of various kinds, 00103 // each of which understands operator==. Thus we can have 00104 // a composite key in which the first field is a TypeKey and the 00105 // second is a string. Below is an anonymous 00106 // union that we use to store the actual token being compared. 00107 // The enum allows us to access the union correctly. If we 00108 // were to put these data into the derivative classes, we 00109 // would end up having to cast the argument of operator==(IfdKey &k) 00110 // to a specific type before we could do the ==. This seems 00111 // cleaner. This is slightly gross, but (1) we really do gain 00112 // something (2) Once we've handled int,string, and TypeKeys, 00113 // we are basically done, i.e., we don't expect much extension 00114 // here. 00115 00116 keyKind _myKeyKind; 00117 // Originally, getKeyKind was virtual. But that was too slow. It 00118 // is reasonable to consider this a difference in value rather than 00119 // difference in behavior, so I've made getKeyKind a non-virtual 00120 // accessor to _myKeyKind and we set _myKeyKind in the ctors. 00121 00122 int _myCardinality; 00123 // See accessor. 00124 00125 union { 00126 int intVal; 00127 unsigned int uintVal; 00128 char* strVal; 00129 }; 00130 00131 00132 friend class IfdIntKey; 00133 friend class IfdStrKey; 00134 friend class IfdTypeKeyIFace; 00135 friend class IfdCompositeKey; 00136 friend class BdbOdfIfdTypeKeyIFace; 00137 // We need to declare these classes as friends because, for 00138 // example, IntKey::op==( IfdKey& k) must get at k.intVal, which 00139 // is protected. Even though all of the IfdKey derivatives inherit 00140 // from IfdKey, the rule is that you can only get at protected 00141 // data in your *own* class, so IntKey can not get at IfdKey::intVal, 00142 // only IntKey::intVal. 00143 00144 friend unsigned ifdKeyHash(const IfdDictKey& k); 00145 00146 private: 00147 virtual void make_vtab( void ) const; 00148 00149 // Copy ctor and assignment op. 00150 // Not sure what to do about these. I think they may not 00151 // make any sense, e.g., what if someone has IfdIntKey ik, IfdStrKey sk, 00152 // and tries to do ik=sk? That is nonsense. It may be OK to do 00153 // a copy ctor and implement it via clone; however, I will just turn 00154 // off the copy ctor for now too. If someone needs it, ask me 00155 // and I'll think more about it. 00156 // 00157 00158 IfdKey( const IfdKey &) { ::abort(); } 00159 IfdKey& operator=( IfdKey &) { if ( this != 0 ) ::abort(); return *this; } 00160 }; 00161 00162 00163 //***************************************************************************** 00164 inline 00165 int 00166 IfdKey::cardinality(void) const { 00167 //***************************************************************************** 00168 return _myCardinality; 00169 } 00170 00171 //***************************************************************************** 00172 //inline 00173 //IfdKey::keyKind 00174 //IfdKey::getKeyKind( void ) const { 00175 //***************************************************************************** 00176 // return _myKeyKind; 00177 //} 00178 00179 //***************************************************************************** 00180 inline 00181 int 00182 IfdKey::operator != ( const IfdKey &k ) const { 00183 //***************************************************************************** 00184 00185 return ! ( *this == k ); 00186 } 00187 00188 00189 #endif /* IFDKEY_HH */