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