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  * 14 Apr 2012 - (mtc) Added support for boost::hash
17  * 28 Dec 2010 - (mtc) Added cbegin and cend (and crbegin and crend) for C++Ox compatibility.
18  * 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group.
19  *      See <http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#776> or Trac issue #3168
20  *      Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow)
21  * 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow)
22  * 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis)
23  * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries.
24  * 05 Aug 2001 - minor update (Nico Josuttis)
25  * 20 Jan 2001 - STLport fix (Beman Dawes)
26  * 29 Sep 2000 - Initial Revision (Nico Josuttis)
27  *
28  * Jan 29, 2004
29  */
30 #ifndef BOOST_ARRAY_HPP
31 #define BOOST_ARRAY_HPP
32 
33 #include <boost/detail/workaround.hpp>
34 
35 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
36 # pragma warning(push)
37 # pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe
38 # pragma warning(disable:4510) // boost::array<T,N>' : default constructor could not be generated
39 # pragma warning(disable:4610) // warning C4610: class 'boost::array<T,N>' can never be instantiated - user defined constructor required
40 #endif
41 
42 #include <cstddef>
43 #include <stdexcept>
44 #include <boost/assert.hpp>
45 #include <boost/swap.hpp>
46 
47 // Handles broken standard libraries better than <iterator>
48 #include <boost/detail/iterator.hpp>
49 #include <boost/throw_exception.hpp>
50 #include <boost/functional/hash_fwd.hpp>
51 #include <algorithm>
52 
53 // FIXES for broken compilers
54 #include <boost/config.hpp>
55 
56 
57 namespace boost {
58 
59     template<class T, std::size_t N>
60     class array {
61       public:
62         T elems[N];    // fixed-size array of elements of type T
63 
64       public:
65         // type definitions
66         typedef T              value_type;
67         typedef T*             iterator;
68         typedef const T*       const_iterator;
69         typedef T&             reference;
70         typedef const T&       const_reference;
71         typedef std::size_t    size_type;
72         typedef std::ptrdiff_t difference_type;
73 
74         // iterator support
begin()75         iterator        begin()       { return elems; }
begin() const76         const_iterator  begin() const { return elems; }
cbegin() const77         const_iterator cbegin() const { return elems; }
78 
end()79         iterator        end()       { return elems+N; }
end() const80         const_iterator  end() const { return elems+N; }
cend() const81         const_iterator cend() const { return elems+N; }
82 
83         // reverse iterator support
84 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
85         typedef std::reverse_iterator<iterator> reverse_iterator;
86         typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
87 #elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
88         // workaround for broken reverse_iterator in VC7
89         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator,
90                                       reference, iterator, reference> > reverse_iterator;
91         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator,
92                                       const_reference, iterator, reference> > const_reverse_iterator;
93 #elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
94         typedef std::reverse_iterator<iterator, std::random_access_iterator_tag,
95               value_type, reference, iterator, difference_type> reverse_iterator;
96         typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
97               value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
98 #else
99         // workaround for broken reverse_iterator implementations
100         typedef std::reverse_iterator<iterator,T> reverse_iterator;
101         typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
102 #endif
103 
rbegin()104         reverse_iterator rbegin() { return reverse_iterator(end()); }
rbegin() const105         const_reverse_iterator rbegin() const {
106             return const_reverse_iterator(end());
107         }
crbegin() const108         const_reverse_iterator crbegin() const {
109             return const_reverse_iterator(end());
110         }
111 
rend()112         reverse_iterator rend() { return reverse_iterator(begin()); }
rend() const113         const_reverse_iterator rend() const {
114             return const_reverse_iterator(begin());
115         }
crend() const116         const_reverse_iterator crend() const {
117             return const_reverse_iterator(begin());
118         }
119 
120         // operator[]
operator [](size_type i)121         reference operator[](size_type i)
122         {
123             BOOST_ASSERT_MSG( i < N, "out of range" );
124             return elems[i];
125         }
126 
operator [](size_type i) const127         const_reference operator[](size_type i) const
128         {
129             BOOST_ASSERT_MSG( i < N, "out of range" );
130             return elems[i];
131         }
132 
133         // at() with range check
at(size_type i)134         reference at(size_type i) { rangecheck(i); return elems[i]; }
at(size_type i) const135         const_reference at(size_type i) const { rangecheck(i); return elems[i]; }
136 
137         // front() and back()
front()138         reference front()
139         {
140             return elems[0];
141         }
142 
front() const143         const_reference front() const
144         {
145             return elems[0];
146         }
147 
back()148         reference back()
149         {
150             return elems[N-1];
151         }
152 
back() const153         const_reference back() const
154         {
155             return elems[N-1];
156         }
157 
158         // size is constant
size()159         static size_type size() { return N; }
empty()160         static bool empty() { return false; }
max_size()161         static size_type max_size() { return N; }
162         enum { static_size = N };
163 
164         // swap (note: linear complexity)
swap(array<T,N> & y)165         void swap (array<T,N>& y) {
166             for (size_type i = 0; i < N; ++i)
167                 boost::swap(elems[i],y.elems[i]);
168         }
169 
170         // direct access to data (read-only)
data() const171         const T* data() const { return elems; }
data()172         T* data() { return elems; }
173 
174         // use array as C array (direct read/write access to data)
c_array()175         T* c_array() { return elems; }
176 
177         // assignment with type conversion
178         template <typename T2>
operator =(const array<T2,N> & rhs)179         array<T,N>& operator= (const array<T2,N>& rhs) {
180             std::copy(rhs.begin(),rhs.end(), begin());
181             return *this;
182         }
183 
184         // assign one value to all elements
assign(const T & value)185         void assign (const T& value) { fill ( value ); }    // A synonym for fill
fill(const T & value)186         void fill   (const T& value)
187         {
188             std::fill_n(begin(),size(),value);
189         }
190 
191         // check range (may be private because it is static)
rangecheck(size_type i)192         static void rangecheck (size_type i) {
193             if (i >= size()) {
194                 std::out_of_range e("array<>: index out of range");
195                 boost::throw_exception(e);
196             }
197         }
198 
199     };
200 
201 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
202     template< class T >
203     class array< T, 0 > {
204 
205       public:
206         // type definitions
207         typedef T              value_type;
208         typedef T*             iterator;
209         typedef const T*       const_iterator;
210         typedef T&             reference;
211         typedef const T&       const_reference;
212         typedef std::size_t    size_type;
213         typedef std::ptrdiff_t difference_type;
214 
215         // iterator support
begin()216         iterator        begin()       { return       iterator( reinterpret_cast<       T * >( this ) ); }
begin() const217         const_iterator  begin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); }
cbegin() const218         const_iterator cbegin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); }
219 
end()220         iterator        end()       { return  begin(); }
end() const221         const_iterator  end() const { return  begin(); }
cend() const222         const_iterator cend() const { return cbegin(); }
223 
224         // reverse iterator support
225 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
226         typedef std::reverse_iterator<iterator> reverse_iterator;
227         typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
228 #elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
229         // workaround for broken reverse_iterator in VC7
230         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator,
231                                       reference, iterator, reference> > reverse_iterator;
232         typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator,
233                                       const_reference, iterator, reference> > const_reverse_iterator;
234 #elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
235         typedef std::reverse_iterator<iterator, std::random_access_iterator_tag,
236               value_type, reference, iterator, difference_type> reverse_iterator;
237         typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
238               value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
239 #else
240         // workaround for broken reverse_iterator implementations
241         typedef std::reverse_iterator<iterator,T> reverse_iterator;
242         typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
243 #endif
244 
rbegin()245         reverse_iterator rbegin() { return reverse_iterator(end()); }
rbegin() const246         const_reverse_iterator rbegin() const {
247             return const_reverse_iterator(end());
248         }
crbegin() const249         const_reverse_iterator crbegin() const {
250             return const_reverse_iterator(end());
251         }
252 
rend()253         reverse_iterator rend() { return reverse_iterator(begin()); }
rend() const254         const_reverse_iterator rend() const {
255             return const_reverse_iterator(begin());
256         }
crend() const257         const_reverse_iterator crend() const {
258             return const_reverse_iterator(begin());
259         }
260 
261         // operator[]
operator [](size_type)262         reference operator[](size_type /*i*/)
263         {
264             return failed_rangecheck();
265         }
266 
operator [](size_type) const267         const_reference operator[](size_type /*i*/) const
268         {
269             return failed_rangecheck();
270         }
271 
272         // at() with range check
at(size_type)273         reference at(size_type /*i*/)               {   return failed_rangecheck(); }
at(size_type) const274         const_reference at(size_type /*i*/) const   {   return failed_rangecheck(); }
275 
276         // front() and back()
front()277         reference front()
278         {
279             return failed_rangecheck();
280         }
281 
front() const282         const_reference front() const
283         {
284             return failed_rangecheck();
285         }
286 
back()287         reference back()
288         {
289             return failed_rangecheck();
290         }
291 
back() const292         const_reference back() const
293         {
294             return failed_rangecheck();
295         }
296 
297         // size is constant
size()298         static size_type size() { return 0; }
empty()299         static bool empty() { return true; }
max_size()300         static size_type max_size() { return 0; }
301         enum { static_size = 0 };
302 
swap(array<T,0> &)303         void swap (array<T,0>& /*y*/) {
304         }
305 
306         // direct access to data (read-only)
data() const307         const T* data() const { return 0; }
data()308         T* data() { return 0; }
309 
310         // use array as C array (direct read/write access to data)
c_array()311         T* c_array() { return 0; }
312 
313         // assignment with type conversion
314         template <typename T2>
operator =(const array<T2,0> &)315         array<T,0>& operator= (const array<T2,0>& ) {
316             return *this;
317         }
318 
319         // assign one value to all elements
assign(const T & value)320         void assign (const T& value) { fill ( value ); }
fill(const T &)321         void fill   (const T& ) {}
322 
323         // check range (may be private because it is static)
failed_rangecheck()324         static reference failed_rangecheck () {
325                 std::out_of_range e("attempt to access element of an empty array");
326                 boost::throw_exception(e);
327 #if defined(BOOST_NO_EXCEPTIONS) || (!defined(BOOST_MSVC) && !defined(__PATHSCALE__))
328                 //
329                 // We need to return something here to keep
330                 // some compilers happy: however we will never
331                 // actually get here....
332                 //
333                 static T placeholder;
334                 return placeholder;
335 #endif
336             }
337     };
338 #endif
339 
340     // comparisons
341     template<class T, std::size_t N>
operator ==(const array<T,N> & x,const array<T,N> & y)342     bool operator== (const array<T,N>& x, const array<T,N>& y) {
343         return std::equal(x.begin(), x.end(), y.begin());
344     }
345     template<class T, std::size_t N>
operator <(const array<T,N> & x,const array<T,N> & y)346     bool operator< (const array<T,N>& x, const array<T,N>& y) {
347         return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end());
348     }
349     template<class T, std::size_t N>
operator !=(const array<T,N> & x,const array<T,N> & y)350     bool operator!= (const array<T,N>& x, const array<T,N>& y) {
351         return !(x==y);
352     }
353     template<class T, std::size_t N>
operator >(const array<T,N> & x,const array<T,N> & y)354     bool operator> (const array<T,N>& x, const array<T,N>& y) {
355         return y<x;
356     }
357     template<class T, std::size_t N>
operator <=(const array<T,N> & x,const array<T,N> & y)358     bool operator<= (const array<T,N>& x, const array<T,N>& y) {
359         return !(y<x);
360     }
361     template<class T, std::size_t N>
operator >=(const array<T,N> & x,const array<T,N> & y)362     bool operator>= (const array<T,N>& x, const array<T,N>& y) {
363         return !(x<y);
364     }
365 
366     // global swap()
367     template<class T, std::size_t N>
swap(array<T,N> & x,array<T,N> & y)368     inline void swap (array<T,N>& x, array<T,N>& y) {
369         x.swap(y);
370     }
371 
372 #if defined(__SUNPRO_CC)
373 //  Trac ticket #4757; the Sun Solaris compiler can't handle
374 //  syntax like 'T(&get_c_array(boost::array<T,N>& arg))[N]'
375 //
376 //  We can't just use this for all compilers, because the
377 //      borland compilers can't handle this form.
378     namespace detail {
379        template <typename T, std::size_t N> struct c_array
380        {
381            typedef T type[N];
382        };
383     }
384 
385    // Specific for boost::array: simply returns its elems data member.
386    template <typename T, std::size_t N>
get_c_array(boost::array<T,N> & arg)387    typename detail::c_array<T,N>::type& get_c_array(boost::array<T,N>& arg)
388    {
389        return arg.elems;
390    }
391 
392    // Specific for boost::array: simply returns its elems data member.
393    template <typename T, std::size_t N>
get_c_array(const boost::array<T,N> & arg)394    typename const detail::c_array<T,N>::type& get_c_array(const boost::array<T,N>& arg)
395    {
396        return arg.elems;
397    }
398 #else
399 // Specific for boost::array: simply returns its elems data member.
400     template <typename T, std::size_t N>
401     T(&get_c_array(boost::array<T,N>& arg))[N]
402     {
403         return arg.elems;
404     }
405 
406     // Const version.
407     template <typename T, std::size_t N>
get_c_array(const boost::array<T,N> & arg)408     const T(&get_c_array(const boost::array<T,N>& arg))[N]
409     {
410         return arg.elems;
411     }
412 #endif
413 
414 #if 0
415     // Overload for std::array, assuming that std::array will have
416     // explicit conversion functions as discussed at the WG21 meeting
417     // in Summit, March 2009.
418     template <typename T, std::size_t N>
419     T(&get_c_array(std::array<T,N>& arg))[N]
420     {
421         return static_cast<T(&)[N]>(arg);
422     }
423 
424     // Const version.
425     template <typename T, std::size_t N>
426     const T(&get_c_array(const std::array<T,N>& arg))[N]
427     {
428         return static_cast<T(&)[N]>(arg);
429     }
430 #endif
431 
432 
433     template<class T, std::size_t N>
434     std::size_t hash_value(const array<T,N>& arr)
435     {
436         return boost::hash_range(arr.begin(), arr.end());
437     }
438 
439 } /* namespace boost */
440 
441 
442 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
443 # pragma warning(pop)
444 #endif
445 
446 #endif /*BOOST_ARRAY_HPP*/
447