Fully qualify the header filenames for doxygen.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / XMLObjectChildrenList.h
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * @file xmltooling/util/XMLObjectChildrenList.h
19  * 
20  * STL-compatible container wrapper
21  */
22
23 #ifndef __xmltooling_list_h__
24 #define __xmltooling_list_h__
25
26 #include <xmltooling/exceptions.h>
27 #include <xmltooling/XMLObject.h>
28
29 #include <list>
30
31 /**
32  * Shorthand for an XMLObjectChildrenList wrapped around a vector
33  * 
34  * @param type  the type of object in the vector
35  */
36 #define VectorOf(type) xmltooling::XMLObjectChildrenList< std::vector<type*> >
37
38 /**
39  * Shorthand for an XMLObjectChildrenList wrapped around a list
40  * 
41  * @param type  the type of object in the list
42  */
43 #define ListOf(type) xmltooling::XMLObjectChildrenList< std::list<type*> >
44
45 /**
46  * Shorthand for an XMLObjectChildrenList wrapped around a deque
47  * 
48  * @param type  the type of object in the deque
49  */
50 #define DequeOf(type) xmltooling::XMLObjectChildrenList< std::deque<type*> >
51
52 /**
53  * Shorthand for an XMLObjectPairList wrapped around a vector
54  * 
55  * @param type1  the first type of object in the vector
56  * @param type2  the second type of object in the vector
57  */
58 #define VectorOfPairs(type1,type2) xmltooling::XMLObjectPairList< std::vector< std::pair<type1*,type2*> > >
59
60 /**
61  * Shorthand for an XMLObjectPairList wrapped around a list
62  * 
63  * @param type1  the first type of object in the vector
64  * @param type2  the second type of object in the vector
65  */
66 #define ListOfPairs(type1,type2) xmltooling::XMLObjectPairList< std::list< std::pair<type1*,type2*> > >
67
68 /**
69  * Shorthand for an XMLObjectPairList wrapped around a deque
70  * 
71  * @param type1  the first type of object in the vector
72  * @param type2  the second type of object in the vector
73  */
74 #define DequeOfPairs(type1,type2) xmltooling::XMLObjectPairList< std::deque< std::pair<type1*,type2*> > >
75
76 namespace xmltooling {
77
78     // Forward reference
79     template <class _Tx, class _Ty=XMLObject> class XMLObjectChildrenList;
80     template <class _Tx, class _Ty=XMLObject> class XMLObjectPairList;
81
82     /**
83      * STL iterator that mediates access to an iterator over typed XML children.
84      * @param _Ty   a bidrectional sequence of the subtype to iterate over
85      */
86     template <class _Ty>
87     class XMLObjectChildrenIterator
88     {
89         /// @cond OFF
90         typename _Ty::iterator m_iter;
91         template <class _Tx, class _Tz> friend class XMLObjectChildrenList;
92         template <class _Tx, class _Tz> friend class XMLObjectPairList;
93     public:
94         typedef typename _Ty::iterator::iterator_category iterator_category;
95         typedef typename _Ty::iterator::value_type value_type;
96         typedef typename _Ty::iterator::reference reference;
97         typedef typename _Ty::iterator::pointer pointer;
98         typedef typename _Ty::const_iterator::reference const_reference;
99         typedef typename _Ty::const_iterator::pointer const_pointer;
100         typedef typename _Ty::iterator::difference_type difference_type;
101
102         XMLObjectChildrenIterator() {
103         }
104
105         XMLObjectChildrenIterator(typename _Ty::iterator iter) {
106             m_iter=iter;
107         }
108
109         const_reference operator*() const {
110             return *m_iter;
111         }
112
113         const_reference operator->() const {
114             return *(m_iter.operator->());
115         }
116
117         XMLObjectChildrenIterator& operator++() {
118             // preincrement
119             ++m_iter;
120             return (*this);
121         }
122
123         XMLObjectChildrenIterator& operator--() {
124             // predecrement
125             --m_iter;
126             return (*this);
127         }
128
129         XMLObjectChildrenIterator operator++(int) {
130             // postincrement
131             XMLObjectChildrenIterator _Tmp = *this;
132             ++*this;
133             return (_Tmp);
134         }
135
136         XMLObjectChildrenIterator operator--(int) {
137             // postdecrement
138             XMLObjectChildrenIterator _Tmp = *this;
139             --*this;
140             return (_Tmp);
141         }
142
143         XMLObjectChildrenIterator& operator+=(difference_type _Off) {
144             // increment by integer
145             m_iter += _Off;
146             return (*this);
147         }
148
149         XMLObjectChildrenIterator operator+(difference_type _Off) const {
150             // return this + integer
151             return m_iter + _Off;
152         }
153
154         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
155             // decrement by integer
156             return (*this += -_Off);
157         }
158
159         XMLObjectChildrenIterator operator-(difference_type _Off) const {
160             // return this - integer
161             XMLObjectChildrenIterator _Tmp = *this;
162             return (_Tmp -= _Off);
163         }
164
165         difference_type operator-(const XMLObjectChildrenIterator& _Right) const {
166             // return difference of iterators
167             return m_iter - _Right.m_iter;
168         }
169
170         const_reference operator[](difference_type _Off) const {
171             // subscript
172             return (*(*this + _Off));
173         }
174
175         bool operator==(const XMLObjectChildrenIterator &_Right) const {
176                     // test for iterator equality
177                     return (m_iter == _Right.m_iter);
178             }
179
180             bool operator!=(const XMLObjectChildrenIterator &_Right) const {
181                     // test for iterator inequality
182                     return (!(m_iter == _Right.m_iter));
183             }
184         /// @endcond
185     };
186
187     /**
188      * STL-compatible container that mediates access to underlying lists of typed XML children.
189      * @param _Tx   the subtype container to encapsulate
190      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
191      */
192     template <class Container, class _Ty>
193     class XMLObjectChildrenList
194     {
195         Container& m_container;
196         typename std::list<_Ty*>* m_list;
197         typename std::list<_Ty*>::iterator m_fence;
198         XMLObject* m_parent;
199
200         public:
201         /// @cond OFF
202         typedef typename Container::value_type value_type;
203         typedef typename Container::reference reference;
204         typedef typename Container::const_reference const_reference;
205         typedef typename Container::difference_type difference_type;
206         typedef typename Container::size_type size_type;
207
208         // We override the iterator types with our constrained wrapper.
209         typedef XMLObjectChildrenIterator<Container> iterator;
210         typedef XMLObjectChildrenIterator<Container> const_iterator;
211         /// @endcond
212
213         /**
214          * Constructor to expose a typed collection of children backed by a list of a base type.
215          *
216          * @param parent    parent object of the collection
217          * @param sublist   underlying container to expose
218          * @param backing   pointer to backing list for children, if any
219          * @param ins_fence a marker designating where new children of this type should be added
220          */
221         XMLObjectChildrenList(
222             XMLObject* parent,
223             Container& sublist,
224             typename std::list<_Ty*>* backing,
225             typename std::list<_Ty*>::iterator ins_fence
226             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
227         }
228
229         /// @cond OFF
230
231         size_type size() const {
232             // return length of sequence
233             return m_container.size();
234         }
235
236         bool empty() const {
237             // test if sequence is empty
238             return m_container.empty();
239         }
240
241         iterator begin() {
242             // return iterator for beginning of mutable sequence
243             return m_container.begin();
244         }
245
246         iterator end() {
247             // return iterator for end of mutable sequence
248             return m_container.end();
249         }
250
251         const_iterator begin() const {
252             // return iterator for beginning of const sequence
253             return m_container.begin();
254         }
255
256         const_iterator end() const {
257             // return iterator for end of const sequence
258             return m_container.end();
259         }
260
261         const_reference at(size_type _Pos) const {
262             // subscript nonmutable sequence with checking
263             return m_container.at(_Pos);
264         }
265
266         const_reference operator[](size_type _Pos) const {
267             // subscript nonmutable sequence
268             return m_container[_Pos];
269         }
270
271         const_reference front() const {
272             // return first element of nonmutable sequence
273             return m_container.front();
274         }
275
276         const_reference back() const {
277             // return last element of nonmutable sequence
278             return m_container.back();
279         }
280
281         void push_back(const_reference _Val) {
282             setParent(_Val);
283             if (m_list)
284                 m_list->insert(m_fence,_Val);
285             m_container.push_back(_Val);
286         }
287
288         iterator erase(iterator _Where) {
289             removeParent(*_Where);
290             if (m_list)
291                 removeChild(*_Where);
292             else
293                 delete *_Where.m_iter;
294             return m_container.erase(_Where.m_iter);
295         }
296
297         iterator erase(iterator _First, iterator _Last) {
298             for (iterator i=_First; i!=_Last; i++) {
299                 removeParent(*i);
300                 if (m_list)
301                     removeChild(*i);
302                 else
303                     delete *i.m_iter;
304             }
305             return m_container.erase(_First.m_iter,_Last.m_iter);
306         }
307
308         void clear() {
309             erase(begin(),end());
310         }
311
312     private:
313         void setParent(const_reference _Val) {
314             if (_Val->getParent())
315                 throw XMLObjectException("Child object already has a parent.");
316             _Val->setParent(m_parent);
317             _Val->releaseParentDOM(true);
318         }
319
320         void removeParent(const_reference _Val) {
321             if (_Val->getParent()!=m_parent)
322                 throw XMLObjectException("Child object not owned by this parent.");
323             _Val->setParent(NULL);
324             m_parent->releaseParentDOM(true);
325         }
326
327         void removeChild(const_reference _Val) {
328             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
329                 if ((*i)==_Val) {
330                     m_list->erase(i);
331                     delete _Val;
332                     return;
333                 }
334             }
335         }
336         /// @endcond
337     };
338
339     /**
340      * STL-compatible container that mediates access to underlying lists of typed XML children
341      * that come in pairs.
342      * 
343      * @param _Tx   the subtype container to encapsulate
344      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
345      */
346     template <class Container, class _Ty>
347     class XMLObjectPairList
348     {
349         Container& m_container;
350         typename std::list<_Ty*>* m_list;
351         typename std::list<_Ty*>::iterator m_fence;
352         XMLObject* m_parent;
353
354     public:
355         /// @cond OFF
356         typedef typename Container::value_type value_type;
357         typedef typename Container::reference reference;
358         typedef typename Container::const_reference const_reference;
359         typedef typename Container::difference_type difference_type;
360         typedef typename Container::size_type size_type;
361
362         // We override the iterator types with our constrained wrapper.
363         typedef XMLObjectChildrenIterator<Container> iterator;
364         typedef XMLObjectChildrenIterator<Container> const_iterator;
365         /// @endcond
366
367         /**
368          * Constructor to expose a typed collection of pairs backed by a list of a base type.
369          *
370          * @param parent    parent object of the collection
371          * @param sublist   underlying container to expose
372          * @param backing   pointer to backing list for children, if any
373          * @param ins_fence a marker designating where new children of this type should be added
374          */
375         XMLObjectPairList(
376             XMLObject* parent,
377             Container& sublist,
378             typename std::list<_Ty*>* backing,
379             typename std::list<_Ty*>::iterator ins_fence
380             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
381         }
382
383         /// @cond OFF
384
385         size_type size() const {
386             // return length of sequence
387             return m_container.size();
388         }
389
390         bool empty() const {
391             // test if sequence is empty
392             return m_container.empty();
393         }
394
395         iterator begin() {
396             // return iterator for beginning of mutable sequence
397             return m_container.begin();
398         }
399
400         iterator end() {
401             // return iterator for end of mutable sequence
402             return m_container.end();
403         }
404
405         const_iterator begin() const {
406             // return iterator for beginning of const sequence
407             return m_container.begin();
408         }
409
410         const_iterator end() const {
411             // return iterator for end of const sequence
412             return m_container.end();
413         }
414
415         const_reference at(size_type _Pos) const {
416             // subscript nonmutable sequence with checking
417             return m_container.at(_Pos);
418         }
419
420         const_reference operator[](size_type _Pos) const {
421             // subscript nonmutable sequence
422             return m_container[_Pos];
423         }
424
425         const_reference front() const {
426             // return first element of nonmutable sequence
427             return m_container.front();
428         }
429
430         const_reference back() const {
431             // return last element of nonmutable sequence
432             return m_container.back();
433         }
434
435         void push_back(const_reference _Val) {
436             setParent(_Val);
437             if (m_list) {
438                 m_list->insert(m_fence,_Val.first);
439                 m_list->insert(m_fence,_Val.second);
440             }
441             m_container.push_back(_Val);
442         }
443
444         iterator erase(iterator _Where) {
445             removeParent(*_Where);
446             if (m_list)
447                 removeChild(*_Where);
448             else {
449                 delete _Where.m_iter->first;
450                 delete _Where.m_iter->second;
451             }
452             return m_container.erase(_Where.m_iter);
453         }
454
455         iterator erase(iterator _First, iterator _Last) {
456             for (iterator i=_First; i!=_Last; i++) {
457                 removeParent(*i);
458                 if (m_list)
459                     removeChild(*i);
460                 else {
461                     delete i.m_iter->first;
462                     delete i.m_iter->second;
463                 }
464             }
465             return m_container.erase(_First,_Last);
466         }
467
468         void clear() {
469             erase(begin(),end());
470         }
471
472     private:
473         void setParent(const_reference _Val) {
474             if (_Val.first->getParent() || (_Val.second && _Val.second->getParent()))
475                 throw XMLObjectException("One of the child objects already has a parent.");
476             _Val.first->setParent(m_parent);
477             if (_Val.second)
478                 _Val.second->setParent(m_parent);
479             _Val.first->releaseParentDOM(true);
480         }
481
482         void removeParent(const_reference _Val) {
483             if (_Val.first->getParent()!=m_parent || (_Val.second && _Val.second->getParent()!=m_parent))
484                 throw XMLObjectException("One of the child objects not owned by this parent.");
485             _Val.first->setParent(NULL);
486             if (_Val.second)
487                 _Val.second->setParent(NULL);
488             m_parent->releaseParentDOM(true);
489         }
490
491         void removeChild(const_reference _Val) {
492             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
493                 if ((*i)==_Val.first) {
494                     typename std::list<_Ty*>::iterator j=i++;
495                     m_list->erase(j);
496                     m_list->erase(i);
497                     delete _Val.first;
498                     delete _Val.second;
499                     return;
500                 }
501                 i++;
502             }
503         }
504         /// @endcond
505     };
506
507 };
508
509 #endif /* __xmltooling_list_h__ */