0024831: Make iterators of NCollection classes STL-compatible
[occt.git] / src / NCollection / NCollection_StlIterator.hxx
1 // Created on: 2014-04-15
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef NCollection_StlIterator_HeaderFile
17 #define NCollection_StlIterator_HeaderFile
18
19 #include <Standard_Assert.hxx>
20 #include <iterator>
21
22 // This file uses C++11 utilities like std::is_base<>, which are not 
23 // available in some environments (e.g. MSVC includes them since VS 2008).
24 // Hence here we define our own implementation of these tools in namespace opencascade.
25 // When all compilers support this, this namespace can be removed and replaced by std.
26 namespace opencascade
27 {
28   template<bool Condition, typename T>
29   struct enable_if
30   {
31     typedef T type;
32   };
33   
34   template<typename T>
35   struct enable_if<false, T>
36   {
37   };
38   
39   template<typename T1, typename T2>
40   struct is_same
41   {
42     enum { value = 0 };
43   };
44   
45   template<typename T>
46   struct is_same<T, T>
47   {
48     enum { value = 1 };
49   };
50   
51   template<bool Condition, typename TypeTrue, typename TypeFalse>
52   struct conditional
53   {
54     typedef TypeTrue type;
55   };
56
57   template<typename TypeTrue, typename TypeFalse>
58   struct conditional<false, TypeTrue, TypeFalse>
59   {
60     typedef TypeFalse type;
61   };
62 }
63
64 //! Helper class that allows to use NCollection iterators as STL iterators.
65 //! NCollection iterator can be extended to STL iterator of any category by
66 //! adding necessary methods: STL forward iterator requires IsEqual method,
67 //! STL bidirectional iterator requires Previous method, and STL random access
68 //! iterator requires Offset and Differ methods. See NCollection_Vector as
69 //! example of declaring custom STL iterators.
70 template<class Category, class BaseIterator, class ItemType, bool IsConstant>
71 class NCollection_StlIterator : private BaseIterator, 
72   public std::iterator<Category, ItemType, ptrdiff_t,
73                        typename opencascade::conditional<IsConstant, const ItemType*, ItemType*>::type,
74                        typename opencascade::conditional<IsConstant, const ItemType&, ItemType&>::type>
75 {
76 public:
77
78   //! Default constructor
79   NCollection_StlIterator () {}
80
81   //! Constructor from NCollection iterator
82   NCollection_StlIterator (const BaseIterator& theIterator)
83     : BaseIterator (theIterator)
84   { }
85
86   //! Cast from non-const variant to const one
87   NCollection_StlIterator (const NCollection_StlIterator<Category, BaseIterator, ItemType, false>& theIterator)
88     : BaseIterator (theIterator)
89   { }
90
91   //! Assignment of non-const iterator to const one
92   NCollection_StlIterator& operator= (const NCollection_StlIterator<Category, BaseIterator, ItemType, false>& theIterator)
93   {
94     BaseIterator::operator= (theIterator);
95     return *this;
96   }
97
98   friend class NCollection_StlIterator<Category, BaseIterator, ItemType, !IsConstant>;
99
100 protected: //! @name methods related to forward STL iterator
101
102   // Note: Here we use SFINAE (Substitution failure is not an error) to choose
103   // an appropriate method based on template arguments (at instantiation time).
104
105   template<bool Condition>
106   typename opencascade::enable_if<!Condition, ItemType&>::type Reference()
107   {
108     return BaseIterator::ChangeValue();
109   }
110
111   template<bool Condition>
112   typename opencascade::enable_if<Condition, const ItemType&>::type Reference()
113   {
114     return BaseIterator::Value();
115   }
116
117 public: //! @name methods related to forward STL iterator
118
119   //! Test for equality
120   bool operator== (const NCollection_StlIterator& theOther) const
121   {
122     return BaseIterator::More() == theOther.More() &&
123            (!BaseIterator::More() || BaseIterator::IsEqual (theOther));
124   }
125
126   //! Test for inequality
127   bool operator!= (const NCollection_StlIterator& theOther) const
128   {
129     return !(*this == theOther);
130   }
131
132   //! Get reference to current item
133   typename NCollection_StlIterator::reference operator*()
134   {
135     return Reference<IsConstant>();
136   }
137
138   //! Dereferencing operator
139   typename NCollection_StlIterator::pointer operator->()
140   {
141     return &Reference<IsConstant>();
142   }
143
144   //! Prefix increment
145   NCollection_StlIterator& operator++()
146   {
147     BaseIterator::Next();
148     return *this;
149   }
150
151   //! Postfix increment
152   NCollection_StlIterator operator++(int)
153   {
154     const NCollection_StlIterator theOld (*this);
155     ++(*this);
156     return theOld;
157   }
158
159 public: //! @name methods related to bidirectional STL iterator
160   
161   //! Prefix decrement
162   NCollection_StlIterator& operator--()
163   {
164     Standard_STATIC_ASSERT((opencascade::is_same<std::bidirectional_iterator_tag,Category>::value ||
165                             opencascade::is_same<std::random_access_iterator_tag,Category>::value));
166     BaseIterator::Previous();
167     return *this;
168   }
169   
170   //! Postfix decrement
171   NCollection_StlIterator operator--(int)
172   {
173     NCollection_StlIterator theOld (*this);
174     --(*this);
175     return theOld;
176   }
177   
178 public: //! @name methods related to random access STL iterator
179
180   //! Move forward
181   NCollection_StlIterator& operator+= (typename NCollection_StlIterator::difference_type theOffset)
182   {
183     Standard_STATIC_ASSERT((opencascade::is_same<std::random_access_iterator_tag,Category>::value));
184     BaseIterator::Offset (theOffset);
185     return *this;
186   }
187
188   //! Addition
189   NCollection_StlIterator operator+ (typename NCollection_StlIterator::difference_type theOffset) const
190   {
191     NCollection_StlIterator aTemp (*this);
192     return aTemp += theOffset;
193   }
194
195   //! Move backward
196   NCollection_StlIterator& operator-= (typename NCollection_StlIterator::difference_type theOffset)
197   {
198     return *this += -theOffset;
199   }
200
201   //! Decrease
202   NCollection_StlIterator operator- (typename NCollection_StlIterator::difference_type theOffset) const
203   {
204     NCollection_StlIterator aTemp (*this);
205     return aTemp += -theOffset;
206   }
207
208   //! Difference
209   typename NCollection_StlIterator::difference_type operator- (const NCollection_StlIterator& theOther) const
210   {
211     Standard_STATIC_ASSERT((opencascade::is_same<std::random_access_iterator_tag,Category>::value));
212     return BaseIterator::Differ (theOther);
213   }
214
215   //! Get item at offset from current
216   typename NCollection_StlIterator::reference operator[] (typename NCollection_StlIterator::difference_type theOffset) const
217   {
218     return *(*this + theOffset);
219   }
220   
221   //! Comparison
222   bool operator< (const NCollection_StlIterator& theOther) const
223   {
224     return (*this - theOther) < 0;
225   }
226
227   //! Comparison
228   bool operator> (const NCollection_StlIterator& theOther) const
229   {
230     return theOther < *this;
231   }
232
233   //! Comparison
234   bool operator<= (const NCollection_StlIterator& theOther) const
235   {
236     return !(theOther < *this);
237   }
238
239   //! Comparison
240   bool operator>= (const NCollection_StlIterator& theOther) const
241   {
242     return !(*this < theOther);
243   }
244 };
245
246 #endif // NCollection_StlIterator_HeaderFile