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