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