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