"latest"
[boost:array.git] / include / boost / array.hpp
1 /* The following code declares class array,
2  * an STL container (as wrapper) for arrays of constant size.
3  *
4  * See
5  *      http://www.boost.org/libs/array/
6  * for documentation.
7  *
8  * The original author site is at: http://www.josuttis.com/
9  *
10  * (C) Copyright Nicolai M. Josuttis 2001.
11  *
12  * Distributed under the Boost Software License, Version 1.0. (See
13  * accompanying file LICENSE_1_0.txt or copy at
14  * http://www.boost.org/LICENSE_1_0.txt)
15  *
16  * 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group.
17  *      See <http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#776> or Trac issue #3168
18  *      Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow)
19  * 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow)
20  * 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis)
21  * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries.
22  * 05 Aug 2001 - minor update (Nico Josuttis)
23  * 20 Jan 2001 - STLport fix (Beman Dawes)
24  * 29 Sep 2000 - Initial Revision (Nico Josuttis)
25  *
26  * Jan 29, 2004
27  */
28 #ifndef BOOST_ARRAY_HPP
29 #define BOOST_ARRAY_HPP
30
31 #include <boost/detail/workaround.hpp>
32
33 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)  
34 # pragma warning(push)  
35 # pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe
36 # pragma warning(disable:4510) // boost::array<T,N>' : default constructor could not be generated 
37 # pragma warning(disable:4610) // warning C4610: class 'boost::array<T,N>' can never be instantiated - user defined constructor required 
38 #endif
39
40 #include <cstddef>
41 #include <stdexcept>
42 #include <boost/assert.hpp>
43 #include <boost/swap.hpp>
44
45 // Handles broken standard libraries better than <iterator>
46 #include <boost/detail/iterator.hpp>
47 #include <boost/throw_exception.hpp>
48 #include <algorithm>
49
50 // FIXES for broken compilers
51 #include <boost/config.hpp>
52
53
54 namespace boost {
55
56     template<class T, std::size_t N>
57     class array {
58       public:
59         T elems[N];    // fixed-size array of elements of type T
60
61       public:
62         // type definitions
63         typedef T              value_type;
64         typedef T*             iterator;
65         typedef const T*       const_iterator;
66         typedef T&             reference;
67         typedef const T&       const_reference;
68         typedef std::size_t    size_type;
69         typedef std::ptrdiff_t difference_type;
70
71         // iterator support
72         iterator begin() { return elems; }
73         const_iterator begin() const { return elems; }
74         iterator end() { return elems+N; }
75         const_iterator end() const { return elems+N; }
76
77         // reverse iterator support
78 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
79         typedef std::reverse_iterator<iterator> reverse_iterator;
80         typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
81 #elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
82         // workaround for broken reverse_iterator in VC7
83         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator,
84                                       reference, iterator, reference> > reverse_iterator;
85         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator,
86                                       const_reference, iterator, reference> > const_reverse_iterator;
87 #elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) 
88         typedef std::reverse_iterator<iterator, std::random_access_iterator_tag, 
89               value_type, reference, iterator, difference_type> reverse_iterator; 
90         typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
91               value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
92 #else
93         // workaround for broken reverse_iterator implementations
94         typedef std::reverse_iterator<iterator,T> reverse_iterator;
95         typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
96 #endif
97
98         reverse_iterator rbegin() { return reverse_iterator(end()); }
99         const_reverse_iterator rbegin() const {
100             return const_reverse_iterator(end());
101         }
102         reverse_iterator rend() { return reverse_iterator(begin()); }
103         const_reverse_iterator rend() const {
104             return const_reverse_iterator(begin());
105         }
106
107         // operator[]
108         reference operator[](size_type i) 
109         { 
110             BOOST_ASSERT( i < N && "out of range" ); 
111             return elems[i];
112         }
113         
114         const_reference operator[](size_type i) const 
115         {     
116             BOOST_ASSERT( i < N && "out of range" ); 
117             return elems[i]; 
118         }
119
120         // at() with range check
121         reference at(size_type i) { rangecheck(i); return elems[i]; }
122         const_reference at(size_type i) const { rangecheck(i); return elems[i]; }
123     
124         // front() and back()
125         reference front() 
126         { 
127             return elems[0]; 
128         }
129         
130         const_reference front() const 
131         {
132             return elems[0];
133         }
134         
135         reference back() 
136         { 
137             return elems[N-1]; 
138         }
139         
140         const_reference back() const 
141         { 
142             return elems[N-1]; 
143         }
144
145         // size is constant
146         static size_type size() { return N; }
147         static bool empty() { return false; }
148         static size_type max_size() { return N; }
149         enum { static_size = N };
150
151         // swap (note: linear complexity)
152         void swap (array<T,N>& y) {
153             for (size_type i = 0; i < N; ++i)
154                 boost::swap(elems[i],y.elems[i]);
155         }
156
157         // direct access to data (read-only)
158         const T* data() const { return elems; }
159         T* data() { return elems; }
160
161         // use array as C array (direct read/write access to data)
162         T* c_array() { return elems; }
163
164         // assignment with type conversion
165         template <typename T2>
166         array<T,N>& operator= (const array<T2,N>& rhs) {
167             std::copy(rhs.begin(),rhs.end(), begin());
168             return *this;
169         }
170
171         // assign one value to all elements
172         void assign (const T& value) { fill ( value ); }    // A synonym for fill
173         void fill   (const T& value)
174         {
175             std::fill_n(begin(),size(),value);
176         }
177
178         // check range (may be private because it is static)
179         static void rangecheck (size_type i) {
180             if (i >= size()) {
181                 std::out_of_range e("array<>: index out of range");
182                 boost::throw_exception(e);
183             }
184         }
185
186     };
187
188 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
189     template< class T >
190     class array< T, 0 > {
191
192       public:
193         // type definitions
194         typedef T              value_type;
195         typedef T*             iterator;
196         typedef const T*       const_iterator;
197         typedef T&             reference;
198         typedef const T&       const_reference;
199         typedef std::size_t    size_type;
200         typedef std::ptrdiff_t difference_type;
201
202         // iterator support
203         iterator begin() { return iterator( reinterpret_cast< T * >( this ) ); }
204         const_iterator begin() const { return const_iterator(  reinterpret_cast< const T * >( this ) ); }
205         iterator end() { return begin(); }
206         const_iterator end() const { return begin(); }
207
208         // reverse iterator support
209 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
210         typedef std::reverse_iterator<iterator> reverse_iterator;
211         typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
212 #elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
213         // workaround for broken reverse_iterator in VC7
214         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator,
215                                       reference, iterator, reference> > reverse_iterator;
216         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator,
217                                       const_reference, iterator, reference> > const_reverse_iterator;
218 #elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) 
219         typedef std::reverse_iterator<iterator, std::random_access_iterator_tag, 
220               value_type, reference, iterator, difference_type> reverse_iterator; 
221         typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
222               value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
223 #else
224         // workaround for broken reverse_iterator implementations
225         typedef std::reverse_iterator<iterator,T> reverse_iterator;
226         typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
227 #endif
228
229         reverse_iterator rbegin() { return reverse_iterator(end()); }
230         const_reverse_iterator rbegin() const {
231             return const_reverse_iterator(end());
232         }
233         reverse_iterator rend() { return reverse_iterator(begin()); }
234         const_reverse_iterator rend() const {
235             return const_reverse_iterator(begin());
236         }
237
238         // operator[]
239         reference operator[](size_type /*i*/)
240         {
241             return failed_rangecheck();
242         }
243
244         const_reference operator[](size_type /*i*/) const
245         {
246             return failed_rangecheck();
247         }
248
249         // at() with range check
250         reference at(size_type /*i*/)               {   return failed_rangecheck(); }
251         const_reference at(size_type /*i*/) const   {   return failed_rangecheck(); }
252
253         // front() and back()
254         reference front()
255         {
256             return failed_rangecheck();
257         }
258
259         const_reference front() const
260         {
261             return failed_rangecheck();
262         }
263
264         reference back()
265         {
266             return failed_rangecheck();
267         }
268
269         const_reference back() const
270         {
271             return failed_rangecheck();
272         }
273
274         // size is constant
275         static size_type size() { return 0; }
276         static bool empty() { return true; }
277         static size_type max_size() { return 0; }
278         enum { static_size = 0 };
279
280         void swap (array<T,0>& /*y*/) {
281         }
282
283         // direct access to data (read-only)
284         const T* data() const { return 0; }
285         T* data() { return 0; }
286
287         // use array as C array (direct read/write access to data)
288         T* c_array() { return 0; }
289
290         // assignment with type conversion
291         template <typename T2>
292         array<T,0>& operator= (const array<T2,0>& ) {
293             return *this;
294         }
295
296         // assign one value to all elements
297         void assign (const T& value) { fill ( value ); }
298         void fill   (const T& ) {}
299         
300         // check range (may be private because it is static)
301         static reference failed_rangecheck () {
302                 std::out_of_range e("attempt to access element of an empty array");
303                 boost::throw_exception(e);
304 #if defined(BOOST_NO_EXCEPTIONS) || !defined(BOOST_MSVC)
305                 //
306                 // We need to return something here to keep
307                 // some compilers happy: however we will never
308                 // actually get here....
309                 //
310                 static T placeholder;
311                 return placeholder;
312 #endif
313             }
314     };
315 #endif
316
317     // comparisons
318     template<class T, std::size_t N>
319     bool operator== (const array<T,N>& x, const array<T,N>& y) {
320         return std::equal(x.begin(), x.end(), y.begin());
321     }
322     template<class T, std::size_t N>
323     bool operator< (const array<T,N>& x, const array<T,N>& y) {
324         return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end());
325     }
326     template<class T, std::size_t N>
327     bool operator!= (const array<T,N>& x, const array<T,N>& y) {
328         return !(x==y);
329     }
330     template<class T, std::size_t N>
331     bool operator> (const array<T,N>& x, const array<T,N>& y) {
332         return y<x;
333     }
334     template<class T, std::size_t N>
335     bool operator<= (const array<T,N>& x, const array<T,N>& y) {
336         return !(y<x);
337     }
338     template<class T, std::size_t N>
339     bool operator>= (const array<T,N>& x, const array<T,N>& y) {
340         return !(x<y);
341     }
342
343     // global swap()
344     template<class T, std::size_t N>
345     inline void swap (array<T,N>& x, array<T,N>& y) {
346         x.swap(y);
347     }
348
349     // Specific for boost::array: simply returns its elems data member.
350     template <typename T, std::size_t N>
351     T(&get_c_array(boost::array<T,N>& arg))[N]
352     {
353         return arg.elems;
354     }
355     
356     // Const version.
357     template <typename T, std::size_t N>
358     const T(&get_c_array(const boost::array<T,N>& arg))[N]
359     {
360         return arg.elems;
361     }
362
363 #if 0
364     // Overload for std::array, assuming that std::array will have
365     // explicit conversion functions as discussed at the WG21 meeting
366     // in Summit, March 2009.
367     template <typename T, std::size_t N>
368     T(&get_c_array(std::array<T,N>& arg))[N]
369     {
370         return static_cast<T(&)[N]>(arg);
371     }
372     
373     // Const version.
374     template <typename T, std::size_t N>
375     const T(&get_c_array(const std::array<T,N>& arg))[N]
376     {
377         return static_cast<T(&)[N]>(arg);
378     }
379 #endif
380
381 } /* namespace boost */
382
383
384 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)  
385 # pragma warning(pop)  
386 #endif 
387
388 #endif /*BOOST_ARRAY_HPP*/