c9955fb8677a20708ec3aeb794f9b7cf0ed2d3cc
[shibboleth/cpp-xmltooling.git] / xmltooling / util / XMLObjectChildrenList.h
1 /*
2  *  Copyright 2001-2010 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      *
85      * @param Container type of container
86      * @param _Ty       a bidrectional iterator to guard
87      */
88     template <class Container, typename _Ty>
89     class XMLObjectChildrenIterator
90     {
91         /// @cond OFF
92         _Ty m_iter;
93         template <class _Tx, class _Tz> friend class XMLObjectChildrenList;
94         template <class _Tx, class _Tz> friend class XMLObjectPairList;
95     public:
96 #ifdef HAVE_ITERATOR_TRAITS
97         typedef typename std::iterator_traits<_Ty>::iterator_category iterator_category;
98         typedef typename std::iterator_traits<_Ty>::value_type value_type;
99         typedef typename std::iterator_traits<_Ty>::difference_type difference_type;
100         typedef typename std::iterator_traits<_Ty>::pointer pointer;
101         typedef typename std::iterator_traits<_Ty>::reference reference;
102 #else
103         typedef typename _Ty::iterator_category iterator_category;
104         typedef typename _Ty::value_type value_type;
105         typedef typename _Ty::difference_type difference_type;
106         typedef typename _Ty::pointer pointer;
107         typedef typename _Ty::reference reference;
108 #endif
109         typedef typename Container::const_reference const_reference;
110         typedef typename Container::const_pointer const_pointer;
111
112         XMLObjectChildrenIterator() {
113         }
114
115         XMLObjectChildrenIterator(_Ty iter) {
116             m_iter=iter;
117         }
118
119         const_reference operator*() const {
120             return *m_iter;
121         }
122
123         const_reference operator->() const {
124             return *m_iter;
125         }
126
127         XMLObjectChildrenIterator& operator++() {
128             // preincrement
129             ++m_iter;
130             return (*this);
131         }
132
133         XMLObjectChildrenIterator& operator--() {
134             // predecrement
135             --m_iter;
136             return (*this);
137         }
138
139         XMLObjectChildrenIterator operator++(int) {
140             // postincrement
141             XMLObjectChildrenIterator _Tmp = *this;
142             ++*this;
143             return (_Tmp);
144         }
145
146         XMLObjectChildrenIterator operator--(int) {
147             // postdecrement
148             XMLObjectChildrenIterator _Tmp = *this;
149             --*this;
150             return (_Tmp);
151         }
152
153         XMLObjectChildrenIterator& operator+=(difference_type _Off) {
154             // increment by integer
155             m_iter += _Off;
156             return (*this);
157         }
158
159         XMLObjectChildrenIterator operator+(difference_type _Off) const {
160             // return this + integer
161             return m_iter + _Off;
162         }
163
164         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
165             // decrement by integer
166             return (*this += -_Off);
167         }
168
169         XMLObjectChildrenIterator operator-(difference_type _Off) const {
170             // return this - integer
171             XMLObjectChildrenIterator _Tmp = *this;
172             return (_Tmp -= _Off);
173         }
174
175         difference_type operator-(const XMLObjectChildrenIterator& _Right) const {
176             // return difference of iterators
177             return m_iter - _Right.m_iter;
178         }
179
180         const_reference operator[](difference_type _Off) const {
181             // subscript
182             return (*(*this + _Off));
183         }
184
185         bool operator==(const XMLObjectChildrenIterator &_Right) const {
186                     // test for iterator equality
187                     return (m_iter == _Right.m_iter);
188             }
189
190             bool operator!=(const XMLObjectChildrenIterator &_Right) const {
191                     // test for iterator inequality
192                     return (!(m_iter == _Right.m_iter));
193             }
194             
195             bool operator<(const XMLObjectChildrenIterator &_Right) const {
196                 return (m_iter < _Right.m_iter);
197             }
198         /// @endcond
199     };
200
201 #ifndef HAVE_ITERATOR_TRAITS
202     /**
203      * STL iterator that mediates access to an iterator that's a pointer.
204      *
205      * @param Container type of container
206      * @param _Ty       the type of object being referenced
207      */
208     template <class Container, typename _Ty>
209     class XMLObjectChildrenIterator<Container, _Ty*>
210     {
211         /// @cond OFF
212         typename _Ty* m_iter;
213         template <class _Tx, class _Tz> friend class XMLObjectChildrenList;
214         template <class _Tx, class _Tz> friend class XMLObjectPairList;
215     public:
216         typedef std::random_access_iterator_tag iterator_category;
217         typedef _Ty value_type;
218         typedef ptrdiff_t difference_type;
219         typedef _Ty* pointer;
220         typedef _Ty& reference;
221         typedef const _Ty& const_reference;
222         typedef const _Ty* const_pointer;
223
224         XMLObjectChildrenIterator() {
225         }
226
227         XMLObjectChildrenIterator(_Ty* iter) {
228             m_iter=iter;
229         }
230
231         const_reference operator*() const {
232             return *m_iter;
233         }
234
235         const_reference operator->() const {
236             return *m_iter;
237         }
238
239         XMLObjectChildrenIterator& operator++() {
240             // preincrement
241             ++m_iter;
242             return (*this);
243         }
244
245         XMLObjectChildrenIterator& operator--() {
246             // predecrement
247             --m_iter;
248             return (*this);
249         }
250
251         XMLObjectChildrenIterator operator++(int) {
252             // postincrement
253             XMLObjectChildrenIterator _Tmp = *this;
254             ++*this;
255             return (_Tmp);
256         }
257
258         XMLObjectChildrenIterator operator--(int) {
259             // postdecrement
260             XMLObjectChildrenIterator _Tmp = *this;
261             --*this;
262             return (_Tmp);
263         }
264
265         XMLObjectChildrenIterator& operator+=(difference_type _Off) {
266             // increment by integer
267             m_iter += _Off;
268             return (*this);
269         }
270
271         XMLObjectChildrenIterator operator+(difference_type _Off) const {
272             // return this + integer
273             return m_iter + _Off;
274         }
275
276         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
277             // decrement by integer
278             return (*this += -_Off);
279         }
280
281         XMLObjectChildrenIterator operator-(difference_type _Off) const {
282             // return this - integer
283             XMLObjectChildrenIterator _Tmp = *this;
284             return (_Tmp -= _Off);
285         }
286
287         difference_type operator-(const XMLObjectChildrenIterator& _Right) const {
288             // return difference of iterators
289             return m_iter - _Right.m_iter;
290         }
291
292         const_reference operator[](difference_type _Off) const {
293             // subscript
294             return (*(*this + _Off));
295         }
296
297         bool operator==(const XMLObjectChildrenIterator &_Right) const {
298                     // test for iterator equality
299                     return (m_iter == _Right.m_iter);
300             }
301
302             bool operator!=(const XMLObjectChildrenIterator &_Right) const {
303                     // test for iterator inequality
304                     return (!(m_iter == _Right.m_iter));
305             }
306             
307             bool operator<(const XMLObjectChildrenIterator &_Right) const {
308                 return (m_iter < _Right.m_iter);
309             }
310         /// @endcond
311     };
312
313     /**
314      * STL iterator that mediates access to an iterator that's a const pointer.
315      *
316      * @param Container type of container
317      * @param _Ty       the type of object being referenced
318      */
319     template <class Container, typename _Ty>
320     class XMLObjectChildrenIterator<Container, const _Ty*>
321     {
322         /// @cond OFF
323         typename const _Ty* m_iter;
324         template <class _Tx, class _Tz> friend class XMLObjectChildrenList;
325         template <class _Tx, class _Tz> friend class XMLObjectPairList;
326     public:
327         typedef std::random_access_iterator_tag iterator_category;
328         typedef _Ty value_type;
329         typedef ptrdiff_t difference_type;
330         typedef const _Ty* pointer;
331         typedef const _Ty& reference;
332         typedef const _Ty& const_reference;
333         typedef const _Ty* const_pointer;
334
335         XMLObjectChildrenIterator() {
336         }
337
338         XMLObjectChildrenIterator(_Ty* iter) {
339             m_iter=iter;
340         }
341
342         const_reference operator*() const {
343             return *m_iter;
344         }
345
346         const_reference operator->() const {
347             return *m_iter;
348         }
349
350         XMLObjectChildrenIterator& operator++() {
351             // preincrement
352             ++m_iter;
353             return (*this);
354         }
355
356         XMLObjectChildrenIterator& operator--() {
357             // predecrement
358             --m_iter;
359             return (*this);
360         }
361
362         XMLObjectChildrenIterator operator++(int) {
363             // postincrement
364             XMLObjectChildrenIterator _Tmp = *this;
365             ++*this;
366             return (_Tmp);
367         }
368
369         XMLObjectChildrenIterator operator--(int) {
370             // postdecrement
371             XMLObjectChildrenIterator _Tmp = *this;
372             --*this;
373             return (_Tmp);
374         }
375
376         XMLObjectChildrenIterator& operator+=(difference_type _Off) {
377             // increment by integer
378             m_iter += _Off;
379             return (*this);
380         }
381
382         XMLObjectChildrenIterator operator+(difference_type _Off) const {
383             // return this + integer
384             return m_iter + _Off;
385         }
386
387         XMLObjectChildrenIterator& operator-=(difference_type _Off) {
388             // decrement by integer
389             return (*this += -_Off);
390         }
391
392         XMLObjectChildrenIterator operator-(difference_type _Off) const {
393             // return this - integer
394             XMLObjectChildrenIterator _Tmp = *this;
395             return (_Tmp -= _Off);
396         }
397
398         difference_type operator-(const XMLObjectChildrenIterator& _Right) const {
399             // return difference of iterators
400             return m_iter - _Right.m_iter;
401         }
402
403         const_reference operator[](difference_type _Off) const {
404             // subscript
405             return (*(*this + _Off));
406         }
407
408         bool operator==(const XMLObjectChildrenIterator &_Right) const {
409                     // test for iterator equality
410                     return (m_iter == _Right.m_iter);
411             }
412
413             bool operator!=(const XMLObjectChildrenIterator &_Right) const {
414                     // test for iterator inequality
415                     return (!(m_iter == _Right.m_iter));
416             }
417             
418             bool operator<(const XMLObjectChildrenIterator &_Right) const {
419                 return (m_iter < _Right.m_iter);
420             }
421         /// @endcond
422     };
423 #endif
424
425     /**
426      * STL-compatible container that mediates access to underlying lists of typed XML children.
427      * @param _Tx   the subtype container to encapsulate
428      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
429      */
430     template <class Container, class _Ty>
431     class XMLObjectChildrenList
432     {
433         Container& m_container;
434         typename std::list<_Ty*>* m_list;
435         typename std::list<_Ty*>::iterator m_fence;
436         XMLObject* m_parent;
437
438         public:
439         /// @cond OFF
440         typedef typename Container::value_type value_type;
441         typedef typename Container::reference reference;
442         typedef typename Container::const_reference const_reference;
443         typedef typename Container::difference_type difference_type;
444         typedef typename Container::size_type size_type;
445
446         // We override the iterator types with our constrained wrapper.
447         typedef XMLObjectChildrenIterator<Container, typename Container::iterator> iterator;
448         typedef XMLObjectChildrenIterator<Container, typename Container::const_iterator> const_iterator;
449         /// @endcond
450
451         /**
452          * Constructor to expose a typed collection of children backed by a list of a base type.
453          *
454          * @param parent    parent object of the collection
455          * @param sublist   underlying container to expose
456          * @param backing   pointer to backing list for children, if any
457          * @param ins_fence a marker designating where new children of this type should be added
458          */
459         XMLObjectChildrenList(
460             XMLObject* parent,
461             Container& sublist,
462             typename std::list<_Ty*>* backing,
463             typename std::list<_Ty*>::iterator ins_fence
464             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
465         }
466
467         /// @cond OFF
468
469         size_type size() const {
470             // return length of sequence
471             return m_container.size();
472         }
473
474         bool empty() const {
475             // test if sequence is empty
476             return m_container.empty();
477         }
478
479         iterator begin() {
480             // return iterator for beginning of mutable sequence
481             return m_container.begin();
482         }
483
484         iterator end() {
485             // return iterator for end of mutable sequence
486             return m_container.end();
487         }
488
489         const_iterator begin() const {
490             // return iterator for beginning of const sequence
491             return const_cast<const Container&>(m_container).begin();
492         }
493
494         const_iterator end() const {
495             // return iterator for end of const sequence
496             return const_cast<const Container&>(m_container).end();
497         }
498
499         const_reference at(size_type _Pos) const {
500             // subscript nonmutable sequence with checking
501             return m_container.at(_Pos);
502         }
503
504         const_reference operator[](size_type _Pos) const {
505             // subscript nonmutable sequence
506             return m_container[_Pos];
507         }
508
509         const_reference front() const {
510             // return first element of nonmutable sequence
511             return m_container.front();
512         }
513
514         const_reference back() const {
515             // return last element of nonmutable sequence
516             return m_container.back();
517         }
518
519         void push_back(const_reference _Val) {
520             setParent(_Val);
521             if (m_list)
522                 m_list->insert(m_fence,_Val);
523             m_container.push_back(_Val);
524         }
525
526         iterator erase(iterator _Where) {
527             removeParent(*_Where);
528             if (m_list)
529                 removeChild(*_Where);
530             else
531                 delete *_Where.m_iter;
532             return m_container.erase(_Where.m_iter);
533         }
534
535         iterator erase(iterator _First, iterator _Last) {
536             for (iterator i=_First; i!=_Last; i++) {
537                 removeParent(*i);
538                 if (m_list)
539                     removeChild(*i);
540                 else
541                     delete *i.m_iter;
542             }
543             return m_container.erase(_First.m_iter,_Last.m_iter);
544         }
545
546         void clear() {
547             erase(begin(),end());
548         }
549
550     private:
551         void setParent(const_reference _Val) {
552             if (_Val->getParent())
553                 throw XMLObjectException("Child object already has a parent.");
554             _Val->setParent(m_parent);
555             _Val->releaseParentDOM(true);
556         }
557
558         void removeParent(const_reference _Val) {
559             if (_Val->getParent()!=m_parent)
560                 throw XMLObjectException("Child object not owned by this parent.");
561             _Val->setParent(nullptr);
562             m_parent->releaseParentDOM(true);
563         }
564
565         void removeChild(const_reference _Val) {
566             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
567                 if ((*i)==_Val) {
568                     m_list->erase(i);
569                     delete _Val;
570                     return;
571                 }
572             }
573         }
574         /// @endcond
575     };
576
577     /**
578      * STL-compatible container that mediates access to underlying lists of typed XML children
579      * that come in pairs.
580      * 
581      * @param _Tx   the subtype container to encapsulate
582      * @param _Ty   the base type in the underlying list (defaults to XMLObject)
583      */
584     template <class Container, class _Ty>
585     class XMLObjectPairList
586     {
587         Container& m_container;
588         typename std::list<_Ty*>* m_list;
589         typename std::list<_Ty*>::iterator m_fence;
590         XMLObject* m_parent;
591
592     public:
593         /// @cond OFF
594         typedef typename Container::value_type value_type;
595         typedef typename Container::reference reference;
596         typedef typename Container::const_reference const_reference;
597         typedef typename Container::difference_type difference_type;
598         typedef typename Container::size_type size_type;
599
600         // We override the iterator types with our constrained wrapper.
601         typedef XMLObjectChildrenIterator<Container, typename Container::iterator> iterator;
602         typedef XMLObjectChildrenIterator<Container, typename Container::const_iterator> const_iterator;
603         /// @endcond
604
605         /**
606          * Constructor to expose a typed collection of pairs backed by a list of a base type.
607          *
608          * @param parent    parent object of the collection
609          * @param sublist   underlying container to expose
610          * @param backing   pointer to backing list for children, if any
611          * @param ins_fence a marker designating where new children of this type should be added
612          */
613         XMLObjectPairList(
614             XMLObject* parent,
615             Container& sublist,
616             typename std::list<_Ty*>* backing,
617             typename std::list<_Ty*>::iterator ins_fence
618             ) : m_container(sublist), m_list(backing), m_fence(ins_fence), m_parent(parent) {
619         }
620
621         /// @cond OFF
622
623         size_type size() const {
624             // return length of sequence
625             return m_container.size();
626         }
627
628         bool empty() const {
629             // test if sequence is empty
630             return m_container.empty();
631         }
632
633         iterator begin() {
634             // return iterator for beginning of mutable sequence
635             return m_container.begin();
636         }
637
638         iterator end() {
639             // return iterator for end of mutable sequence
640             return m_container.end();
641         }
642
643         const_iterator begin() const {
644             // return iterator for beginning of const sequence
645             return const_cast<const Container&>(m_container).begin();
646         }
647
648         const_iterator end() const {
649             // return iterator for end of const sequence
650             return const_cast<const Container&>(m_container).end();
651         }
652
653         const_reference at(size_type _Pos) const {
654             // subscript nonmutable sequence with checking
655             return m_container.at(_Pos);
656         }
657
658         const_reference operator[](size_type _Pos) const {
659             // subscript nonmutable sequence
660             return m_container[_Pos];
661         }
662
663         const_reference front() const {
664             // return first element of nonmutable sequence
665             return m_container.front();
666         }
667
668         const_reference back() const {
669             // return last element of nonmutable sequence
670             return m_container.back();
671         }
672
673         void push_back(const_reference _Val) {
674             setParent(_Val);
675             if (m_list) {
676                 m_list->insert(m_fence,_Val.first);
677                 m_list->insert(m_fence,_Val.second);
678             }
679             m_container.push_back(_Val);
680         }
681
682         iterator erase(iterator _Where) {
683             removeParent(*_Where);
684             if (m_list)
685                 removeChild(*_Where);
686             else {
687                 delete _Where.m_iter->first;
688                 delete _Where.m_iter->second;
689             }
690             return m_container.erase(_Where.m_iter);
691         }
692
693         iterator erase(iterator _First, iterator _Last) {
694             for (iterator i=_First; i!=_Last; i++) {
695                 removeParent(*i);
696                 if (m_list)
697                     removeChild(*i);
698                 else {
699                     delete i.m_iter->first;
700                     delete i.m_iter->second;
701                 }
702             }
703             return m_container.erase(_First,_Last);
704         }
705
706         void clear() {
707             erase(begin(),end());
708         }
709
710     private:
711         void setParent(const_reference _Val) {
712             if (_Val.first->getParent() || (_Val.second && _Val.second->getParent()))
713                 throw XMLObjectException("One of the child objects already has a parent.");
714             _Val.first->setParent(m_parent);
715             if (_Val.second)
716                 _Val.second->setParent(m_parent);
717             _Val.first->releaseParentDOM(true);
718         }
719
720         void removeParent(const_reference _Val) {
721             if (_Val.first->getParent()!=m_parent || (_Val.second && _Val.second->getParent()!=m_parent))
722                 throw XMLObjectException("One of the child objects not owned by this parent.");
723             _Val.first->setParent(nullptr);
724             if (_Val.second)
725                 _Val.second->setParent(nullptr);
726             m_parent->releaseParentDOM(true);
727         }
728
729         void removeChild(const_reference _Val) {
730             for (typename std::list<_Ty*>::iterator i=m_list->begin(); i!=m_list->end(); i++) {
731                 if ((*i)==_Val.first) {
732                     typename std::list<_Ty*>::iterator j=i++;
733                     m_list->erase(j);
734                     m_list->erase(i);
735                     delete _Val.first;
736                     delete _Val.second;
737                     return;
738                 }
739                 i++;
740             }
741         }
742         /// @endcond
743     };
744
745 };
746
747 #endif /* __xmltooling_list_h__ */