boost::extents
は、boost::multi_array
の各次元の有効なインデックス範囲を指定するためのオブジェクトです。
#include <boost/multi_array.hpp>
int main()
{
boost::multi_array<float, 2> arr(boost::extents[10][20]);
return 0;
}
また、extent_range
オブジェクトを使うことで最小の添字を指定することができます。
boost::multi_array
では、各次元の添字の範囲は整数の区間で表現されます。
#include <boost/multi_array.hpp>
int main()
{
using boost::multi_array_types::extent_range;
boost::multi_array<float, 2> arr(boost::extents[extent_range(2, 5)][10]);
for (size_t i = 0; i < 2; ++i)
{
// 各次元の始点と要素数を表示
printf("[%zu] %zu, %zu\n", i, arr.index_bases()[i], arr.shape()[i]);
}
// 不正なアクセス
printf("%f\n", arr[0][0]);
return 0;
}
$ # macOS Sierra (10.12) + Homebrew
$ clang sample.cpp -o sample -I /usr/local/include/ -lc++
$ ./sample
[0] 2, 3
[1] 0, 10
Assertion failed: (idx - index_bases[0] >= 0), function access, file /usr/local/include/boost/multi_array/base.hpp, line 135.
Abort trap: 6
※ Boost.MultiArray ではデフォルトで添字の範囲チェックが行われます。
Boost.MultiArray の添字演算子について
boost::extents の実装
boost::extents
は、<boost/multi_array/base.hpp>
で boost::detail::multi_array::extent_gen<0>
型のグローバルオブジェクトとして定義されています。
// 説明に必要な部分のみ抜粋
namespace boost {
namespace multi_array_types {
typedef detail::multi_array::extent_gen<0> extent_gen;
}
multi_array_types::extent_gen extents;
}
extent_gen
は以下の実装になっています。
// 説明に必要な部分のみ抜粋
namespace boost::detail::multi_array {
template <size_t NumRanges>
class extent_gen {
public:
typedef boost::detail::multi_array::index index;
typedef boost::detail::multi_array::size_type size_type;
typedef extent_range<index, size_type> range;
private:
typedef typename range_list_generator<range, NumRanges>::type range_list;
public:
// N 次元の範囲全てを保持するフィールド。
// 実体は boost::array<extent_range, size_t> 。
//
// range_list_generator::type はテンプレートの特殊化により NumRanges = 0 の場合に
// boost::array<extent_range, 1> を返すようになっている。
range_list ranges_;
extent_gen() { }
extent_gen(const extent_gen<NumRanges - 1>& rhs,
const range& a_range)
{
std::copy(rhs.ranges_.begin(), rhs.ranges_.end(), ranges_.begin());
*ranges_.rbegin() = a_range;
}
// extent_gen<N> から extent_gen<N + 1> を返す演算子。
// boost::extents[10] -> boost::extents[10][extent_range(10, 20)] に相当。
extent_gen<NumRanges + 1>
operator[](const range& a_range)
{
return extent_gen<NumRanges + 1>(*this, a_range);
}
// extent_gen<N> から extent_gen<N + 1> を返す演算子。
// boost::extents[10] -> boost::extents[10][20] に相当。
// index の実体は ptrdiff_t
extent_gen<NumRanges + 1>
operator[](index idx)
{
return extent_gen<NumRanges + 1>(*this, range(0, idx));
}
};
}
extent_range
は次元ごとの添字の範囲を表現します。 extent_gen<N>::range
は
extent_gen<N>::range =
boost::detail::multi_array::extent_range<
boost::detail::multi_array::index,
boost::detail::multi_array::size_type
>
boost::detail::multi_array::index = ptrdiff_t
boost::detail::multi_array::size_type = size_t
と展開されるため、extent_range
のテンプレートパラメータは extent_range<ptrdiff_t, size_t>
となります。 したがって、extent_range
のメモリ配置は次のとおり std::pair<ptrdiff_t, ptrdiff_t>
と同じです。
extent_range
には 3 つのコンストラクタと 3 つのメンバ関数があります。
namespace boost::detail::multi_array {
template<typename Extent, typename SizeType>
class extent_range : private std::pair<Extent, Extent> {
typedef std::pair<Extent, Extent> super_type;
public:
typedef Extent index;
typedef SizeType size_type;
extent_range() : super_type(0, 0) { }
extent_range(index finish) :
super_type(0, finish) { }
extent_range(index start, index finish) :
super_type(start, finish) { }
index start() const { return super_type::first; }
index finish() const { return super_type::second; }
size_type size() const { return super_type::second - super_type::first; }
};
}
boost::multi_array コンストラクタでの使用
multi_array
, multi_array_ref
, const_multi_array_ref
のコンストラクタでは、 extent_gen<N>::ranges_
フィールドに直接アクセスすることで配列の範囲を取得しています。
以下は、const_multi_array_ref
のコンストラクタのひとつです。
namespace boost {
class const_multi_array_ref :
public detail::multi_array::multi_array_impl_base<T, NumDims>
{
public:
// ベースポインタと extent_gen から多次元配列のインターフェースを作成します。
explicit const_multi_array_ref(
TPtr base,
const detail::multi_array::extent_gen<NumDims>& ranges) :
base_(base),
storage_(c_storage_order())
{
init_from_extent_gen(ranges);
}
private:
void init_from_extent_gen(
const detail::multi_array::extent_gen<NumDims>& ranges)
{
typedef boost::array<index, NumDims> extent_list;
// 各次元の原点を取得
std::transform(
ranges.ranges_.begin(),
ranges.ranges_.end(),
index_base_list_.begin(),
boost::mem_fun_ref(&extent_range::start)
);
// 各次元の大きさを取得
extent_list extents;
std::transform(
ranges.ranges_.begin(),
ranges.ranges_.end(),
extents.begin(),
boost::mem_fun_ref(&extent_range::size)
);
init_multi_array_ref(extents.begin());
}
};
}
ソースコードのライセンス
// Copyright 2002 The Trustees of Indiana University.
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Boost.MultiArray Library
// Authors: Ronald Garcia
// Jeremy Siek
// Andrew Lumsdaine
// See http://www.boost.org/libs/multi_array for documentation.
参考資料
-
Boost.org multi_array module
https://github.com/boostorg/multi_array -
Boost.MultiArray 使い方とチュートリアル(翻訳)
https://yokaze.github.io/boost-translation-ja/MultiArray/user.html -
boost::indices の解説
https://yokaze.github.io/2017/09/13/