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