annotate DEPENDENCIES/generic/include/boost/multi_array/base.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 // Copyright 2002 The Trustees of Indiana University.
Chris@16 2
Chris@16 3 // Use, modification and distribution is subject to the Boost Software
Chris@16 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 // Boost.MultiArray Library
Chris@16 8 // Authors: Ronald Garcia
Chris@16 9 // Jeremy Siek
Chris@16 10 // Andrew Lumsdaine
Chris@16 11 // See http://www.boost.org/libs/multi_array for documentation.
Chris@16 12
Chris@16 13 #ifndef BASE_RG071801_HPP
Chris@16 14 #define BASE_RG071801_HPP
Chris@16 15
Chris@16 16 //
Chris@16 17 // base.hpp - some implementation base classes for from which
Chris@16 18 // functionality is acquired
Chris@16 19 //
Chris@16 20
Chris@16 21 #include "boost/multi_array/extent_range.hpp"
Chris@16 22 #include "boost/multi_array/extent_gen.hpp"
Chris@16 23 #include "boost/multi_array/index_range.hpp"
Chris@16 24 #include "boost/multi_array/index_gen.hpp"
Chris@16 25 #include "boost/multi_array/storage_order.hpp"
Chris@16 26 #include "boost/multi_array/types.hpp"
Chris@16 27 #include "boost/config.hpp"
Chris@16 28 #include "boost/multi_array/concept_checks.hpp" //for ignore_unused_...
Chris@16 29 #include "boost/mpl/eval_if.hpp"
Chris@16 30 #include "boost/mpl/if.hpp"
Chris@16 31 #include "boost/mpl/size_t.hpp"
Chris@16 32 #include "boost/iterator/reverse_iterator.hpp"
Chris@16 33 #include "boost/static_assert.hpp"
Chris@16 34 #include "boost/type.hpp"
Chris@16 35 #include "boost/assert.hpp"
Chris@16 36 #include <cstddef>
Chris@16 37 #include <memory>
Chris@16 38
Chris@16 39 namespace boost {
Chris@16 40
Chris@16 41 /////////////////////////////////////////////////////////////////////////
Chris@16 42 // class declarations
Chris@16 43 /////////////////////////////////////////////////////////////////////////
Chris@16 44
Chris@16 45 template<typename T, std::size_t NumDims,
Chris@16 46 typename Allocator = std::allocator<T> >
Chris@16 47 class multi_array;
Chris@16 48
Chris@16 49 // This is a public interface for use by end users!
Chris@16 50 namespace multi_array_types {
Chris@16 51 typedef boost::detail::multi_array::size_type size_type;
Chris@16 52 typedef std::ptrdiff_t difference_type;
Chris@16 53 typedef boost::detail::multi_array::index index;
Chris@16 54 typedef detail::multi_array::index_range<index,size_type> index_range;
Chris@16 55 typedef detail::multi_array::extent_range<index,size_type> extent_range;
Chris@16 56 typedef detail::multi_array::index_gen<0,0> index_gen;
Chris@16 57 typedef detail::multi_array::extent_gen<0> extent_gen;
Chris@16 58 }
Chris@16 59
Chris@16 60
Chris@16 61 // boost::extents and boost::indices are now a part of the public
Chris@16 62 // interface. That way users don't necessarily have to create their
Chris@16 63 // own objects. On the other hand, one may not want the overhead of
Chris@16 64 // object creation in small-memory environments. Thus, the objects
Chris@16 65 // can be left undefined by defining BOOST_MULTI_ARRAY_NO_GENERATORS
Chris@16 66 // before loading multi_array.hpp.
Chris@101 67 #ifndef BOOST_MULTI_ARRAY_NO_GENERATORS
Chris@16 68 namespace {
Chris@16 69 multi_array_types::extent_gen extents;
Chris@16 70 multi_array_types::index_gen indices;
Chris@16 71 }
Chris@16 72 #endif // BOOST_MULTI_ARRAY_NO_GENERATORS
Chris@16 73
Chris@16 74 namespace detail {
Chris@16 75 namespace multi_array {
Chris@16 76
Chris@16 77 template <typename T, std::size_t NumDims>
Chris@16 78 class sub_array;
Chris@16 79
Chris@16 80 template <typename T, std::size_t NumDims, typename TPtr = const T*>
Chris@16 81 class const_sub_array;
Chris@16 82
Chris@16 83 template <typename T, typename TPtr, typename NumDims, typename Reference,
Chris@16 84 typename IteratorCategory>
Chris@16 85 class array_iterator;
Chris@16 86
Chris@16 87 template <typename T, std::size_t NumDims, typename TPtr = const T*>
Chris@16 88 class const_multi_array_view;
Chris@16 89
Chris@16 90 template <typename T, std::size_t NumDims>
Chris@16 91 class multi_array_view;
Chris@16 92
Chris@16 93 /////////////////////////////////////////////////////////////////////////
Chris@16 94 // class interfaces
Chris@16 95 /////////////////////////////////////////////////////////////////////////
Chris@16 96
Chris@16 97 class multi_array_base {
Chris@16 98 public:
Chris@16 99 typedef multi_array_types::size_type size_type;
Chris@16 100 typedef multi_array_types::difference_type difference_type;
Chris@16 101 typedef multi_array_types::index index;
Chris@16 102 typedef multi_array_types::index_range index_range;
Chris@16 103 typedef multi_array_types::extent_range extent_range;
Chris@16 104 typedef multi_array_types::index_gen index_gen;
Chris@16 105 typedef multi_array_types::extent_gen extent_gen;
Chris@16 106 };
Chris@16 107
Chris@16 108 //
Chris@16 109 // value_accessor_n
Chris@16 110 // contains the routines for accessing elements from
Chris@16 111 // N-dimensional views.
Chris@16 112 //
Chris@16 113 template<typename T, std::size_t NumDims>
Chris@16 114 class value_accessor_n : public multi_array_base {
Chris@16 115 typedef multi_array_base super_type;
Chris@16 116 public:
Chris@16 117 typedef typename super_type::index index;
Chris@16 118
Chris@16 119 //
Chris@16 120 // public typedefs used by classes that inherit from this base
Chris@16 121 //
Chris@16 122 typedef T element;
Chris@16 123 typedef boost::multi_array<T,NumDims-1> value_type;
Chris@16 124 typedef sub_array<T,NumDims-1> reference;
Chris@16 125 typedef const_sub_array<T,NumDims-1> const_reference;
Chris@16 126
Chris@16 127 protected:
Chris@16 128 // used by array operator[] and iterators to get reference types.
Chris@16 129 template <typename Reference, typename TPtr>
Chris@16 130 Reference access(boost::type<Reference>,index idx,TPtr base,
Chris@16 131 const size_type* extents,
Chris@16 132 const index* strides,
Chris@16 133 const index* index_bases) const {
Chris@16 134
Chris@16 135 BOOST_ASSERT(idx - index_bases[0] >= 0);
Chris@16 136 BOOST_ASSERT(size_type(idx - index_bases[0]) < extents[0]);
Chris@16 137 // return a sub_array<T,NDims-1> proxy object
Chris@16 138 TPtr newbase = base + idx * strides[0];
Chris@16 139 return Reference(newbase,extents+1,strides+1,index_bases+1);
Chris@16 140
Chris@16 141 }
Chris@16 142
Chris@16 143 value_accessor_n() { }
Chris@16 144 ~value_accessor_n() { }
Chris@16 145 };
Chris@16 146
Chris@16 147
Chris@16 148
Chris@16 149 //
Chris@16 150 // value_accessor_one
Chris@16 151 // contains the routines for accessing reference elements from
Chris@16 152 // 1-dimensional views.
Chris@16 153 //
Chris@16 154 template<typename T>
Chris@16 155 class value_accessor_one : public multi_array_base {
Chris@16 156 typedef multi_array_base super_type;
Chris@16 157 public:
Chris@16 158 typedef typename super_type::index index;
Chris@16 159 //
Chris@16 160 // public typedefs for use by classes that inherit it.
Chris@16 161 //
Chris@16 162 typedef T element;
Chris@16 163 typedef T value_type;
Chris@16 164 typedef T& reference;
Chris@16 165 typedef T const& const_reference;
Chris@16 166
Chris@16 167 protected:
Chris@16 168 // used by array operator[] and iterators to get reference types.
Chris@16 169 template <typename Reference, typename TPtr>
Chris@16 170 Reference access(boost::type<Reference>,index idx,TPtr base,
Chris@16 171 const size_type* extents,
Chris@16 172 const index* strides,
Chris@16 173 const index* index_bases) const {
Chris@16 174
Chris@16 175 ignore_unused_variable_warning(index_bases);
Chris@16 176 ignore_unused_variable_warning(extents);
Chris@16 177 BOOST_ASSERT(idx - index_bases[0] >= 0);
Chris@16 178 BOOST_ASSERT(size_type(idx - index_bases[0]) < extents[0]);
Chris@16 179 return *(base + idx * strides[0]);
Chris@16 180 }
Chris@16 181
Chris@16 182 value_accessor_one() { }
Chris@16 183 ~value_accessor_one() { }
Chris@16 184 };
Chris@16 185
Chris@16 186
Chris@16 187 /////////////////////////////////////////////////////////////////////////
Chris@16 188 // choose value accessor begins
Chris@16 189 //
Chris@16 190
Chris@16 191 template <typename T, std::size_t NumDims>
Chris@16 192 struct choose_value_accessor_n {
Chris@16 193 typedef value_accessor_n<T,NumDims> type;
Chris@16 194 };
Chris@16 195
Chris@16 196 template <typename T>
Chris@16 197 struct choose_value_accessor_one {
Chris@16 198 typedef value_accessor_one<T> type;
Chris@16 199 };
Chris@16 200
Chris@16 201 template <typename T, typename NumDims>
Chris@16 202 struct value_accessor_generator {
Chris@16 203 BOOST_STATIC_CONSTANT(std::size_t, dimensionality = NumDims::value);
Chris@16 204
Chris@16 205 typedef typename
Chris@16 206 mpl::eval_if_c<(dimensionality == 1),
Chris@16 207 choose_value_accessor_one<T>,
Chris@16 208 choose_value_accessor_n<T,dimensionality>
Chris@16 209 >::type type;
Chris@16 210 };
Chris@16 211
Chris@16 212 template <class T, class NumDims>
Chris@16 213 struct associated_types
Chris@16 214 : value_accessor_generator<T,NumDims>::type
Chris@16 215 {};
Chris@16 216
Chris@16 217 //
Chris@16 218 // choose value accessor ends
Chris@16 219 /////////////////////////////////////////////////////////////////////////
Chris@16 220
Chris@16 221 // Due to some imprecision in the C++ Standard,
Chris@16 222 // MSVC 2010 is broken in debug mode: it requires
Chris@16 223 // that an Output Iterator have output_iterator_tag in its iterator_category if
Chris@16 224 // that iterator is not bidirectional_iterator or random_access_iterator.
Chris@16 225 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
Chris@16 226 struct mutable_iterator_tag
Chris@16 227 : boost::random_access_traversal_tag, std::input_iterator_tag
Chris@16 228 {
Chris@16 229 operator std::output_iterator_tag() const {
Chris@16 230 return std::output_iterator_tag();
Chris@16 231 }
Chris@16 232 };
Chris@16 233 #endif
Chris@16 234
Chris@16 235 ////////////////////////////////////////////////////////////////////////
Chris@16 236 // multi_array_base
Chris@16 237 ////////////////////////////////////////////////////////////////////////
Chris@16 238 template <typename T, std::size_t NumDims>
Chris@16 239 class multi_array_impl_base
Chris@16 240 :
Chris@16 241 public value_accessor_generator<T,mpl::size_t<NumDims> >::type
Chris@16 242 {
Chris@16 243 typedef associated_types<T,mpl::size_t<NumDims> > types;
Chris@16 244 public:
Chris@16 245 typedef typename types::index index;
Chris@16 246 typedef typename types::size_type size_type;
Chris@16 247 typedef typename types::element element;
Chris@16 248 typedef typename types::index_range index_range;
Chris@16 249 typedef typename types::value_type value_type;
Chris@16 250 typedef typename types::reference reference;
Chris@16 251 typedef typename types::const_reference const_reference;
Chris@16 252
Chris@16 253 template <std::size_t NDims>
Chris@16 254 struct subarray {
Chris@16 255 typedef boost::detail::multi_array::sub_array<T,NDims> type;
Chris@16 256 };
Chris@16 257
Chris@16 258 template <std::size_t NDims>
Chris@16 259 struct const_subarray {
Chris@16 260 typedef boost::detail::multi_array::const_sub_array<T,NDims> type;
Chris@16 261 };
Chris@16 262
Chris@16 263 template <std::size_t NDims>
Chris@16 264 struct array_view {
Chris@16 265 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
Chris@16 266 };
Chris@16 267
Chris@16 268 template <std::size_t NDims>
Chris@16 269 struct const_array_view {
Chris@16 270 public:
Chris@16 271 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
Chris@16 272 };
Chris@16 273
Chris@16 274 //
Chris@16 275 // iterator support
Chris@16 276 //
Chris@16 277 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1600)
Chris@16 278 // Deal with VC 2010 output_iterator_tag requirement
Chris@16 279 typedef array_iterator<T,T*,mpl::size_t<NumDims>,reference,
Chris@16 280 mutable_iterator_tag> iterator;
Chris@16 281 #else
Chris@16 282 typedef array_iterator<T,T*,mpl::size_t<NumDims>,reference,
Chris@16 283 boost::random_access_traversal_tag> iterator;
Chris@16 284 #endif
Chris@16 285 typedef array_iterator<T,T const*,mpl::size_t<NumDims>,const_reference,
Chris@16 286 boost::random_access_traversal_tag> const_iterator;
Chris@16 287
Chris@16 288 typedef ::boost::reverse_iterator<iterator> reverse_iterator;
Chris@16 289 typedef ::boost::reverse_iterator<const_iterator> const_reverse_iterator;
Chris@16 290
Chris@16 291 BOOST_STATIC_CONSTANT(std::size_t, dimensionality = NumDims);
Chris@16 292 protected:
Chris@16 293
Chris@16 294 multi_array_impl_base() { }
Chris@16 295 ~multi_array_impl_base() { }
Chris@16 296
Chris@16 297 // Used by operator() in our array classes
Chris@16 298 template <typename Reference, typename IndexList, typename TPtr>
Chris@16 299 Reference access_element(boost::type<Reference>,
Chris@16 300 const IndexList& indices,
Chris@16 301 TPtr base,
Chris@16 302 const size_type* extents,
Chris@16 303 const index* strides,
Chris@16 304 const index* index_bases) const {
Chris@16 305 boost::function_requires<
Chris@16 306 CollectionConcept<IndexList> >();
Chris@16 307 ignore_unused_variable_warning(index_bases);
Chris@16 308 ignore_unused_variable_warning(extents);
Chris@16 309 #if !defined(NDEBUG) && !defined(BOOST_DISABLE_ASSERTS)
Chris@16 310 for (size_type i = 0; i != NumDims; ++i) {
Chris@16 311 BOOST_ASSERT(indices[i] - index_bases[i] >= 0);
Chris@16 312 BOOST_ASSERT(size_type(indices[i] - index_bases[i]) < extents[i]);
Chris@16 313 }
Chris@16 314 #endif
Chris@16 315
Chris@16 316 index offset = 0;
Chris@16 317 {
Chris@16 318 typename IndexList::const_iterator i = indices.begin();
Chris@16 319 size_type n = 0;
Chris@16 320 while (n != NumDims) {
Chris@16 321 offset += (*i) * strides[n];
Chris@16 322 ++n;
Chris@16 323 ++i;
Chris@16 324 }
Chris@16 325 }
Chris@16 326 return base[offset];
Chris@16 327 }
Chris@16 328
Chris@16 329 template <typename StrideList, typename ExtentList>
Chris@16 330 void compute_strides(StrideList& stride_list, ExtentList& extent_list,
Chris@16 331 const general_storage_order<NumDims>& storage)
Chris@16 332 {
Chris@16 333 // invariant: stride = the stride for dimension n
Chris@16 334 index stride = 1;
Chris@16 335 for (size_type n = 0; n != NumDims; ++n) {
Chris@16 336 index stride_sign = +1;
Chris@16 337
Chris@16 338 if (!storage.ascending(storage.ordering(n)))
Chris@16 339 stride_sign = -1;
Chris@16 340
Chris@16 341 // The stride for this dimension is the product of the
Chris@16 342 // lengths of the ranks minor to it.
Chris@16 343 stride_list[storage.ordering(n)] = stride * stride_sign;
Chris@16 344
Chris@16 345 stride *= extent_list[storage.ordering(n)];
Chris@16 346 }
Chris@16 347 }
Chris@16 348
Chris@16 349 // This calculates the offset to the array base pointer due to:
Chris@16 350 // 1. dimensions stored in descending order
Chris@16 351 // 2. non-zero dimension index bases
Chris@16 352 template <typename StrideList, typename ExtentList, typename BaseList>
Chris@16 353 index
Chris@16 354 calculate_origin_offset(const StrideList& stride_list,
Chris@16 355 const ExtentList& extent_list,
Chris@16 356 const general_storage_order<NumDims>& storage,
Chris@16 357 const BaseList& index_base_list)
Chris@16 358 {
Chris@16 359 return
Chris@16 360 calculate_descending_dimension_offset(stride_list,extent_list,
Chris@16 361 storage) +
Chris@16 362 calculate_indexing_offset(stride_list,index_base_list);
Chris@16 363 }
Chris@16 364
Chris@16 365 // This calculates the offset added to the base pointer that are
Chris@16 366 // caused by descending dimensions
Chris@16 367 template <typename StrideList, typename ExtentList>
Chris@16 368 index
Chris@16 369 calculate_descending_dimension_offset(const StrideList& stride_list,
Chris@16 370 const ExtentList& extent_list,
Chris@16 371 const general_storage_order<NumDims>& storage)
Chris@16 372 {
Chris@16 373 index offset = 0;
Chris@16 374 if (!storage.all_dims_ascending())
Chris@16 375 for (size_type n = 0; n != NumDims; ++n)
Chris@16 376 if (!storage.ascending(n))
Chris@16 377 offset -= (extent_list[n] - 1) * stride_list[n];
Chris@16 378
Chris@16 379 return offset;
Chris@16 380 }
Chris@16 381
Chris@16 382 // This is used to reindex array_views, which are no longer
Chris@16 383 // concerned about storage order (specifically, whether dimensions
Chris@16 384 // are ascending or descending) since the viewed array handled it.
Chris@16 385
Chris@16 386 template <typename StrideList, typename BaseList>
Chris@16 387 index
Chris@16 388 calculate_indexing_offset(const StrideList& stride_list,
Chris@16 389 const BaseList& index_base_list)
Chris@16 390 {
Chris@16 391 index offset = 0;
Chris@16 392 for (size_type n = 0; n != NumDims; ++n)
Chris@16 393 offset -= stride_list[n] * index_base_list[n];
Chris@16 394 return offset;
Chris@16 395 }
Chris@16 396
Chris@16 397 // Slicing using an index_gen.
Chris@16 398 // Note that populating an index_gen creates a type that encodes
Chris@16 399 // both the number of dimensions in the current Array (NumDims), and
Chris@16 400 // the Number of dimensions for the resulting view. This allows the
Chris@16 401 // compiler to fail if the dimensions aren't completely accounted
Chris@16 402 // for. For reasons unbeknownst to me, a BOOST_STATIC_ASSERT
Chris@16 403 // within the member function template does not work. I should add a
Chris@16 404 // note to the documentation specifying that you get a damn ugly
Chris@16 405 // error message if you screw up in your slicing code.
Chris@16 406 template <typename ArrayRef, int NDims, typename TPtr>
Chris@16 407 ArrayRef
Chris@16 408 generate_array_view(boost::type<ArrayRef>,
Chris@16 409 const boost::detail::multi_array::
Chris@16 410 index_gen<NumDims,NDims>& indices,
Chris@16 411 const size_type* extents,
Chris@16 412 const index* strides,
Chris@16 413 const index* index_bases,
Chris@16 414 TPtr base) const {
Chris@16 415
Chris@16 416 boost::array<index,NDims> new_strides;
Chris@16 417 boost::array<index,NDims> new_extents;
Chris@16 418
Chris@16 419 index offset = 0;
Chris@16 420 size_type dim = 0;
Chris@16 421 for (size_type n = 0; n != NumDims; ++n) {
Chris@16 422
Chris@16 423 // Use array specs and input specs to produce real specs.
Chris@16 424 const index default_start = index_bases[n];
Chris@16 425 const index default_finish = default_start+extents[n];
Chris@16 426 const index_range& current_range = indices.ranges_[n];
Chris@16 427 index start = current_range.get_start(default_start);
Chris@16 428 index finish = current_range.get_finish(default_finish);
Chris@16 429 index stride = current_range.stride();
Chris@16 430 BOOST_ASSERT(stride != 0);
Chris@16 431
Chris@16 432 // An index range indicates a half-open strided interval
Chris@16 433 // [start,finish) (with stride) which faces upward when stride
Chris@16 434 // is positive and downward when stride is negative,
Chris@16 435
Chris@16 436 // RG: The following code for calculating length suffers from
Chris@16 437 // some representation issues: if finish-start cannot be represented as
Chris@16 438 // by type index, then overflow may result.
Chris@16 439
Chris@16 440 index len;
Chris@16 441 if ((finish - start) / stride < 0) {
Chris@16 442 // [start,finish) is empty according to the direction imposed by
Chris@16 443 // the stride.
Chris@16 444 len = 0;
Chris@16 445 } else {
Chris@16 446 // integral trick for ceiling((finish-start) / stride)
Chris@16 447 // taking into account signs.
Chris@16 448 index shrinkage = stride > 0 ? 1 : -1;
Chris@16 449 len = (finish - start + (stride - shrinkage)) / stride;
Chris@16 450 }
Chris@16 451
Chris@16 452 // start marks the closed side of the range, so it must lie
Chris@16 453 // exactly in the set of legal indices
Chris@16 454 // with a special case for empty arrays
Chris@16 455 BOOST_ASSERT(index_bases[n] <= start &&
Chris@16 456 ((start <= index_bases[n]+index(extents[n])) ||
Chris@16 457 (start == index_bases[n] && extents[n] == 0)));
Chris@16 458
Chris@16 459 #ifndef BOOST_DISABLE_ASSERTS
Chris@16 460 // finish marks the open side of the range, so it can go one past
Chris@16 461 // the "far side" of the range (the top if stride is positive, the bottom
Chris@16 462 // if stride is negative).
Chris@16 463 index bound_adjustment = stride < 0 ? 1 : 0;
Chris@16 464 BOOST_ASSERT(((index_bases[n] - bound_adjustment) <= finish) &&
Chris@16 465 (finish <= (index_bases[n] + index(extents[n]) - bound_adjustment)));
Chris@16 466 #endif // BOOST_DISABLE_ASSERTS
Chris@16 467
Chris@16 468
Chris@16 469 // the array data pointer is modified to account for non-zero
Chris@16 470 // bases during slicing (see [Garcia] for the math involved)
Chris@16 471 offset += start * strides[n];
Chris@16 472
Chris@16 473 if (!current_range.is_degenerate()) {
Chris@16 474
Chris@16 475 // The stride for each dimension is included into the
Chris@16 476 // strides for the array_view (see [Garcia] for the math involved).
Chris@16 477 new_strides[dim] = stride * strides[n];
Chris@16 478
Chris@16 479 // calculate new extents
Chris@16 480 new_extents[dim] = len;
Chris@16 481 ++dim;
Chris@16 482 }
Chris@16 483 }
Chris@16 484 BOOST_ASSERT(dim == NDims);
Chris@16 485
Chris@16 486 return
Chris@16 487 ArrayRef(base+offset,
Chris@16 488 new_extents,
Chris@16 489 new_strides);
Chris@16 490 }
Chris@16 491
Chris@16 492
Chris@16 493 };
Chris@16 494
Chris@16 495 } // namespace multi_array
Chris@16 496 } // namespace detail
Chris@16 497
Chris@16 498 } // namespace boost
Chris@16 499
Chris@16 500 #endif // BASE_RG071801_HPP