df6b86069e59ba9f989f33f9a0e9323633e22cc6
[shibboleth/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::value_type value_type;
95         typedef typename _Ty::reference reference;
96         typedef typename _Ty::pointer pointer;
97         typedef typename _Ty::const_reference const_reference;
98         typedef typename _Ty::const_pointer const_pointer;
99         typedef typename _Ty::difference_type difference_type;
100
101         XMLObjectChildrenIterator() {
102         }
103
104         XMLObjectChildrenIterator(typename _Ty::iterator iter) {
105             m_iter=iter;
106         }
107
108         const_reference operator*() const {
109             return *m_iter;
110         }
111
112         const_reference operator->() const {
113             return *m_iter;
114         }
115
116         XMLObjectChildrenIterator& operator++() {
117             // preincrement
118             ++m_iter;
119             return (*this);
120         }
121
122         XMLObjectChildrenIterator& operator--() {
123             // predecrement
124             --m_iter;
125             return (*this);
126         }
127
128         XMLObjectChildrenIterator operator++(int) {
129             // postincrement
130             XMLObjectChildrenIterator _Tmp = *this;
131             ++*this;
132             return (_Tmp);
133         }
134
135         XMLObjectChildrenIterator operator--(int) {
136             // postdecrement
137             XMLObjectChildrenIterator _Tmp = *this;
138             --*this;
139             return (_Tmp);
140         }
141
142         XMLObjectChildrenIterator& operator+=(difference_type _Off) {
143             // increment by integer
144             m_iter += _Off;
145             return (*this);
146         }
147
148         XMLObjectChildrenIterator operator+(difference_type _Off) const {
149             // return this + integer
150             return m_iter + _Off;
151         }
152
153         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
154             // decrement by integer
155             return (*this += -_Off);
156         }
157
158         XMLObjectChildrenIterator operator-(difference_type _Off) const {
159             // return this - integer
160             XMLObjectChildrenIterator _Tmp = *this;
161             return (_Tmp -= _Off);
162         }
163
164         difference_type operator-(const XMLObjectChildrenIterator& _Right) const {
165             // return difference of iterators
166             return m_iter - _Right.m_iter;
167         }
168
169         const_reference operator[](difference_type _Off) const {
170             // subscript
171             return (*(*this + _Off));
172         }
173
174         bool operator==(const XMLObjectChildrenIterator &_Right) const {
175                     // test for iterator equality
176                     return (m_iter == _Right.m_iter);
177             }
178
179             bool operator!=(const XMLObjectChildrenIterator &_Right) const {
180                     // test for iterator inequality
181                     return (!(m_iter == _Right.m_iter));
182             }
183         /// @endcond
184     };
185
186     /**
187      * STL-compatible container that mediates access to underlying lists of typed XML children.
188      * @param _Tx   the subtype container to encapsulate
189      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
190      */
191     template <class Container, class _Ty>
192     class XMLObjectChildrenList
193     {
194         Container& m_container;
195         typename std::list<_Ty*>* m_list;
196         typename std::list<_Ty*>::iterator m_fence;
197         XMLObject* m_parent;
198
199         public:
200         /// @cond OFF
201         typedef typename Container::value_type value_type;
202         typedef typename Container::reference reference;
203         typedef typename Container::const_reference const_reference;
204         typedef typename Container::difference_type difference_type;
205         typedef typename Container::size_type size_type;
206
207         // We override the iterator types with our constrained wrapper.
208         typedef XMLObjectChildrenIterator<Container> iterator;
209         typedef XMLObjectChildrenIterator<Container> const_iterator;
210         /// @endcond
211
212         /**
213          * Constructor to expose a typed collection of children backed by a list of a base type.
214          *
215          * @param parent    parent object of the collection
216          * @param sublist   underlying container to expose
217          * @param backing   pointer to backing list for children, if any
218          * @param ins_fence a marker designating where new children of this type should be added
219          */
220         XMLObjectChildrenList(
221             XMLObject* parent,
222             Container& sublist,
223             typename std::list<_Ty*>* backing,
224             typename std::list<_Ty*>::iterator ins_fence
225             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
226         }
227
228         /// @cond OFF
229
230         size_type size() const {
231             // return length of sequence
232             return m_container.size();
233         }
234
235         bool empty() const {
236             // test if sequence is empty
237             return m_container.empty();
238         }
239
240         iterator begin() {
241             // return iterator for beginning of mutable sequence
242             return m_container.begin();
243         }
244
245         iterator end() {
246             // return iterator for end of mutable sequence
247             return m_container.end();
248         }
249
250         const_iterator begin() const {
251             // return iterator for beginning of const sequence
252             return m_container.begin();
253         }
254
255         const_iterator end() const {
256             // return iterator for end of const sequence
257             return m_container.end();
258         }
259
260         const_reference at(size_type _Pos) const {
261             // subscript nonmutable sequence with checking
262             return m_container.at(_Pos);
263         }
264
265         const_reference operator[](size_type _Pos) const {
266             // subscript nonmutable sequence
267             return m_container[_Pos];
268         }
269
270         const_reference front() const {
271             // return first element of nonmutable sequence
272             return m_container.front();
273         }
274
275         const_reference back() const {
276             // return last element of nonmutable sequence
277             return m_container.back();
278         }
279
280         void push_back(const_reference _Val) {
281             setParent(_Val);
282             if (m_list)
283                 m_list->insert(m_fence,_Val);
284             m_container.push_back(_Val);
285         }
286
287         iterator erase(iterator _Where) {
288             removeParent(*_Where);
289             if (m_list)
290                 removeChild(*_Where);
291             else
292                 delete *_Where.m_iter;
293             return m_container.erase(_Where.m_iter);
294         }
295
296         iterator erase(iterator _First, iterator _Last) {
297             for (iterator i=_First; i!=_Last; i++) {
298                 removeParent(*i);
299                 if (m_list)
300                     removeChild(*i);
301                 else
302                     delete *i.m_iter;
303             }
304             return m_container.erase(_First.m_iter,_Last.m_iter);
305         }
306
307         void clear() {
308             erase(begin(),end());
309         }
310
311     private:
312         void setParent(const_reference _Val) {
313             if (_Val->getParent())
314                 throw XMLObjectException("Child object already has a parent.");
315             _Val->setParent(m_parent);
316             _Val->releaseParentDOM(true);
317         }
318
319         void removeParent(const_reference _Val) {
320             if (_Val->getParent()!=m_parent)
321                 throw XMLObjectException("Child object not owned by this parent.");
322             _Val->setParent(NULL);
323             m_parent->releaseParentDOM(true);
324         }
325
326         void removeChild(const_reference _Val) {
327             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
328                 if ((*i)==_Val) {
329                     m_list->erase(i);
330                     delete _Val;
331                     return;
332                 }
333             }
334         }
335         /// @endcond
336     };
337
338     /**
339      * STL-compatible container that mediates access to underlying lists of typed XML children
340      * that come in pairs.
341      * 
342      * @param _Tx   the subtype container to encapsulate
343      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
344      */
345     template <class Container, class _Ty>
346     class XMLObjectPairList
347     {
348         Container& m_container;
349         typename std::list<_Ty*>* m_list;
350         typename std::list<_Ty*>::iterator m_fence;
351         XMLObject* m_parent;
352
353     public:
354         /// @cond OFF
355         typedef typename Container::value_type value_type;
356         typedef typename Container::reference reference;
357         typedef typename Container::const_reference const_reference;
358         typedef typename Container::difference_type difference_type;
359         typedef typename Container::size_type size_type;
360
361         // We override the iterator types with our constrained wrapper.
362         typedef XMLObjectChildrenIterator<Container> iterator;
363         typedef XMLObjectChildrenIterator<Container> const_iterator;
364         /// @endcond
365
366         /**
367          * Constructor to expose a typed collection of pairs backed by a list of a base type.
368          *
369          * @param parent    parent object of the collection
370          * @param sublist   underlying container to expose
371          * @param backing   pointer to backing list for children, if any
372          * @param ins_fence a marker designating where new children of this type should be added
373          */
374         XMLObjectPairList(
375             XMLObject* parent,
376             Container& sublist,
377             typename std::list<_Ty*>* backing,
378             typename std::list<_Ty*>::iterator ins_fence
379             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
380         }
381
382         /// @cond OFF
383
384         size_type size() const {
385             // return length of sequence
386             return m_container.size();
387         }
388
389         bool empty() const {
390             // test if sequence is empty
391             return m_container.empty();
392         }
393
394         iterator begin() {
395             // return iterator for beginning of mutable sequence
396             return m_container.begin();
397         }
398
399         iterator end() {
400             // return iterator for end of mutable sequence
401             return m_container.end();
402         }
403
404         const_iterator begin() const {
405             // return iterator for beginning of const sequence
406             return m_container.begin();
407         }
408
409         const_iterator end() const {
410             // return iterator for end of const sequence
411             return m_container.end();
412         }
413
414         const_reference at(size_type _Pos) const {
415             // subscript nonmutable sequence with checking
416             return m_container.at(_Pos);
417         }
418
419         const_reference operator[](size_type _Pos) const {
420             // subscript nonmutable sequence
421             return m_container[_Pos];
422         }
423
424         const_reference front() const {
425             // return first element of nonmutable sequence
426             return m_container.front();
427         }
428
429         const_reference back() const {
430             // return last element of nonmutable sequence
431             return m_container.back();
432         }
433
434         void push_back(const_reference _Val) {
435             setParent(_Val);
436             if (m_list) {
437                 m_list->insert(m_fence,_Val.first);
438                 m_list->insert(m_fence,_Val.second);
439             }
440             m_container.push_back(_Val);
441         }
442
443         iterator erase(iterator _Where) {
444             removeParent(*_Where);
445             if (m_list)
446                 removeChild(*_Where);
447             else {
448                 delete _Where.m_iter->first;
449                 delete _Where.m_iter->second;
450             }
451             return m_container.erase(_Where.m_iter);
452         }
453
454         iterator erase(iterator _First, iterator _Last) {
455             for (iterator i=_First; i!=_Last; i++) {
456                 removeParent(*i);
457                 if (m_list)
458                     removeChild(*i);
459                 else {
460                     delete i.m_iter->first;
461                     delete i.m_iter->second;
462                 }
463             }
464             return m_container.erase(_First,_Last);
465         }
466
467         void clear() {
468             erase(begin(),end());
469         }
470
471     private:
472         void setParent(const_reference _Val) {
473             if (_Val.first->getParent() || (_Val.second && _Val.second->getParent()))
474                 throw XMLObjectException("One of the child objects already has a parent.");
475             _Val.first->setParent(m_parent);
476             if (_Val.second)
477                 _Val.second->setParent(m_parent);
478             _Val.first->releaseParentDOM(true);
479         }
480
481         void removeParent(const_reference _Val) {
482             if (_Val.first->getParent()!=m_parent || (_Val.second && _Val.second->getParent()!=m_parent))
483                 throw XMLObjectException("One of the child objects not owned by this parent.");
484             _Val.first->setParent(NULL);
485             if (_Val.second)
486                 _Val.second->setParent(NULL);
487             m_parent->releaseParentDOM(true);
488         }
489
490         void removeChild(const_reference _Val) {
491             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
492                 if ((*i)==_Val.first) {
493                     typename std::list<_Ty*>::iterator j=i++;
494                     m_list->erase(j);
495                     m_list->erase(i);
496                     delete _Val.first;
497                     delete _Val.second;
498                     return;
499                 }
500                 i++;
501             }
502         }
503         /// @endcond
504     };
505
506 };
507
508 #endif /* __xmltooling_list_h__ */