1 // This file may be redistributed and modified only under the terms of
2 // the GNU Lesser General Public License (See COPYING for details).
3 // Copyright (C) 2000-2004 Stefanus Du Toit, Aloril and Al Riddoch
4 
5 // $Id$
6 
7 #ifndef ATLAS_OBJECTS_BASEOBJECT_H
8 #define ATLAS_OBJECTS_BASEOBJECT_H
9 
10 #include <Atlas/Message/MEncoder.h>
11 #include <Atlas/Message/Element.h>
12 #include <Atlas/Bridge.h>
13 #include <Atlas/Exception.h>
14 
15 #include <map>
16 #include <list>
17 #include <string>
18 
19 #include <assert.h>
20 
21 namespace Atlas {
22 
23 /// The Atlas high level Objects namespace.
24 ///
25 /// This namespace contains classes used to handle high level Atlas data.
26 namespace Objects {
27 
28 /** An exception indicating the requested attribute does not exist.
29  *
30  * This is thrown by Root::getAttr() [and derivatives thereof!]
31  */
32 class NoSuchAttrException : public Atlas::Exception
33 {
34     /// The name of the attribute that does not exist.
35     std::string m_name;
36   public:
NoSuchAttrException(const std::string & name)37     NoSuchAttrException(const std::string& name) :
38              Atlas::Exception("No such attribute"), m_name(name) {}
39     virtual ~NoSuchAttrException();
40     /// Get the name of the attribute which does not exist.
getName()41     const std::string & getName() const {
42         return m_name;
43     }
44 };
45 
46 static const int BASE_OBJECT_NO = 0;
47 
48 /** Atlas base object class.
49 
50 This is class is the base from which all classes used to represent high
51 level objects are derived. In this release of Atlas-C++, all classes
52 that inherit from BaseObjectData are designed to be used with SmartPtr
53 and should have the suffix Data on the end of their name. All the
54 subclasses of BaseObjectData included with Atlas-C++ are automatically
55 generated from the Atlas spec at release time. For each subclass
56 a typedef is created of a specialisation of SmartPtr aliasing it
57 to the name of the class without the Data suffix. Thus RootOperationData
58 has an associate type RootOperation which is a typedef for
59 SmartPtr<RootOperationData>. Each class also has an associated integer
60 identifier used to identify classes of its type. The SmartPtr class
61 is designed to store unused instances of the data objects in a memory
62 pool, and reuse instances as they are required. In order to re-use
63 instances without re-constructing all their members, a system of flags
64 is used to mark which members are in use. When an instance is re-used
65 these flags are cleared, indicating that none of the members are in use.
66  */
67 class BaseObjectData
68 {
69 public:
70     /// Construct a new BaseObjectData from a subclass.
71     /// Initialises flags to zero, and stores a pointer to the reference
72     /// object that provides default values for all attributes. Subclasses
73     /// must pass in a pointer to their class specific reference object.
74     BaseObjectData(BaseObjectData *defaults);
75 
76     virtual ~BaseObjectData();
77 
78     /// Get class number:
getClassNo()79     int getClassNo() const
80     {
81         return m_class_no;
82     }
83 
getAttrFlags()84     int getAttrFlags() const
85     {
86         return m_attrFlags;
87     }
88 
89     virtual BaseObjectData * copy() const = 0;
90 
91     /// Is this instance of some class?
92     virtual bool instanceOf(int classNo) const;
93 
94     /// Check whether the attribute "name" exists.
95     bool hasAttr(const std::string& name) const;
96     /// Check whether the attribute "name" exists.
97     bool hasAttrFlag(int flag) const;
98     /// Retrieve the attribute "name". Throws NoSuchAttrException if it does
99     /// not exist.
100     const Atlas::Message::Element getAttr(const std::string& name)
101         const;
102     /// Retrieve the attribute "name". Return non-zero if it does
103     /// not exist.
104     virtual int copyAttr(const std::string& name,
105                          Atlas::Message::Element & attr) const;
106     /// Set the attribute "name" to the value given by "attr".
107     virtual void setAttr(const std::string& name,
108                          const Atlas::Message::Element& attr);
109     /// Remove the attribute "name".
110     virtual void removeAttr(const std::string& name);
111     /// Remove the attribute "name".
112     virtual void removeAttrFlag(int flag);
113 
114     /// Convert this object to a Object. This is now legacy, and implemented
115     /// using addToMessage.
116     const Atlas::Message::MapType asMessage() const;
117 
118     /// Write this object to an existing Element
119     virtual void addToMessage(Atlas::Message::MapType &) const;
120 
121     /// Send the contents of this object to a Bridge.
122     virtual void sendContents(Atlas::Bridge & b) const;
123 
124     //move to protected once SmartPtr <-> BaseObject order established
125     inline void incRef();
126     inline void decRef();
127 
128     /// \brief Allocate a new instance of this class, using an existing
129     /// instance if available.
130     ///
131     /// This is the key function for implementing the memory pool
132     /// for the Atlas::Objects API.
alloc()133     static BaseObjectData *alloc() {assert(0); return NULL;} //not callable
134     /// \brief Free an instance of this class, returning it to the memory
135     /// pool.
136     ///
137     /// This function in combination with alloc() handle the memory pool.
138     virtual void free() = 0;
139 
140     class const_iterator;
141 
142     // FIXME should this hold a reference to the object it's
143     // iterating over?
144 
145     /// The iterator first iterates over the contents of m_obj->m_attributes,
146     /// holding an iterator to the attributes map in m_I. When m_I reaches
147     /// the end, it iterates through the named attributes in each of the
148     /// classes, starting with the terminal child and working its way
149     /// up to the ultimate parent, BaseObjectData. It stores the
150     /// class number in m_current_class and the name of the current
151     /// attribute in m_val.first. Since BaseObjectData has no
152     /// named attributes, an iterator with m_current_class == BASE_OBJECT_NO
153     /// is considered to be the end of the map.
154     /// The iterator constructor has an argument which lets you begin() at the
155     /// first named attribute in some class, and only iterate through
156     /// that class and its parents. The same iterator, treated as an
157     /// end(), lets you iterate through all attributes which are either
158     /// named in derived classes or in m_attributes.
159     class iterator
160     {
161     public:
162         friend class BaseObjectData;
163         friend class const_iterator;
164 
iterator()165         iterator() : m_obj(0), m_val("", *this) {}
iterator(const iterator & I)166         iterator(const iterator& I) : m_obj(I.m_obj),
167             m_current_class(I.m_current_class),
168             m_I(I.m_I), m_val(I.m_val.first, *this) {}
169         iterator(BaseObjectData& obj, int current_class);
170 
171         // default destructor is fine unless we hold a reference to m_obj
172 
173         iterator& operator=(const iterator& I);
174 
175         iterator& operator++(); // preincrement
176 
177         inline iterator operator++(int); // postincrement
178 
179         bool operator==(const iterator& I) const;
180 
181         bool operator!=(const iterator& I) const {return !operator==(I);}
182 
183         class PsuedoElement
184         {
185             public:
PsuedoElement(const iterator & I)186                 PsuedoElement(const iterator& I) : m_I(I) {}
187 
188                 operator Message::Element() const;
189                 // this acts on const PsuedoElement instead of PsuedoElement
190                 // so that we can assign to attributes refered to by
191                 // a const iterator& (as opposed to a const_iterator, where
192                 // we can't, but that's done later)
193                 const PsuedoElement& operator=(const Message::Element& val) const;
194 
195             private:
196                 const iterator& m_I;
197         };
198 
199         friend class PsuedoElement;
200 
201         typedef std::pair<std::string,PsuedoElement> value_type;
202 
203         const value_type& operator*() const {return m_val;}
204         const value_type* operator->() const {return &m_val;}
205 
206     private:
207         BaseObjectData *m_obj; // pointer to object whose args we're iterating
208         int m_current_class; // m_class_no for current class in the iteration
209         Message::MapType::iterator m_I; // iterator in m_obj->m_attributes
210         value_type m_val;
211     };
212     friend class iterator;
213 
214     // FIXME should this hold a reference to the object it's
215     // iterating over?
216     class const_iterator
217     {
218     public:
219         friend class BaseObjectData;
220 
const_iterator()221         const_iterator() : m_obj(0), m_val("", *this) {}
const_iterator(const const_iterator & I)222         const_iterator(const const_iterator& I) : m_obj(I.m_obj),
223             m_current_class(I.m_current_class),
224             m_I(I.m_I), m_val(I.m_val.first, *this) {}
const_iterator(const iterator & I)225         const_iterator(const iterator& I) : m_obj(I.m_obj),
226             m_current_class(I.m_current_class),
227             m_I(I.m_I), m_val(I.m_val.first, *this) {}
228         const_iterator(const BaseObjectData& obj, int current_class);
229 
230         // default destructor is fine unless we hold a reference to m_obj
231 
232         const_iterator& operator=(const const_iterator& I);
233 
234         const_iterator& operator++(); // preincrement
235 
236         inline const_iterator operator++(int); // postincrement
237 
238         bool operator==(const const_iterator& I) const;
239 
240         bool operator!=(const const_iterator& I) const {return !operator==(I);}
241 
242         class PsuedoElement
243         {
244             public:
PsuedoElement(const const_iterator & I)245                 PsuedoElement(const const_iterator& I) : m_I(I) {}
246 
247                 operator Message::Element() const;
248 
249             private:
250                 const const_iterator& m_I;
251         };
252 
253         friend class PsuedoElement;
254 
255         typedef std::pair<std::string,PsuedoElement> value_type;
256 
257         const value_type& operator*() const {return m_val;}
258         const value_type* operator->() const {return &m_val;}
259 
260     private:
261         const BaseObjectData *m_obj; // pointer to object whose args we're iterating
262         int m_current_class; // m_class_no for current class in the iteration
263         Message::MapType::const_iterator m_I; // const_iterator in m_obj->m_attributes
264         value_type m_val;
265     };
266 
267     friend class const_iterator;
268 
begin()269     iterator begin() {return iterator(*this, -1);}
end()270     iterator end() {return iterator(*this, BASE_OBJECT_NO);}
271     iterator find(const std::string&);
272 
begin()273     const_iterator begin() const {return const_iterator(*this, -1);}
end()274     const_iterator end() const {return const_iterator(*this, BASE_OBJECT_NO);}
275     const_iterator find(const std::string&) const;
276 
277 protected:
278 
279     /// Find the class which contains the attribute "name".
280     virtual int getAttrClass(const std::string& name) const;
281 
282     /// Find the flag for the attribute "name".
283     virtual int getAttrFlag(const std::string& name) const;
284 
285     /// Iterate over the attributes of this instance.
286     virtual void iterate(int& current_class, std::string& attr) const;
287 
288     int m_class_no; //each class has different enum
289     int m_refCount; //how many instances
290     BaseObjectData *m_defaults;
291     //this will be defined in each subclass separately, so no need here for it
292     //static BaseObjectData *begin;
293     BaseObjectData *m_next;
294     std::map<std::string, Atlas::Message::Element> m_attributes;
295     // is attribute in this object or in default object?
296     int m_attrFlags;
297 };
298 
incRef()299 void BaseObjectData::incRef() {
300     m_refCount++;
301 }
302 
decRef()303 void BaseObjectData::decRef() {
304     //why zero based refCount? avoids one m_refCount-- ;-)
305     assert( m_refCount >= 0 );
306     if(!m_refCount) {
307         free();
308         return;
309     }
310     m_refCount--;
311 }
312 
313 BaseObjectData::iterator BaseObjectData::iterator::operator++(int) // postincrement
314 {
315     iterator tmp = *this;
316     operator++();
317     return tmp;
318 }
319 
320 BaseObjectData::const_iterator BaseObjectData::const_iterator::operator++(int) // postincrement
321 {
322     const_iterator tmp = *this;
323     operator++();
324     return tmp;
325 }
326 
327 
328 } } // namespace Atlas::Objects
329 
330 #endif
331