添字アクセスのサポート
ヘッダ <boost/python/indexing/indexing_suite.hpp> 、ヘッダ <boost/python/indexing/vector_indexing_suite.hpp>
はじめに
indexing は、添字アクセス可能(indexable)な C++ コンテナを Python へ容易にエクスポートするための Boost.Python の機能である。添字アクセス可能なコンテナとは operator[] によりランダムアクセス可能なコンテナである(例:std::vector)。
std::vector のようなどこにでもある添字アクセス可能な C++ コンテナを Python へエクスポートするのに必要な機能は Boost.Python はすべて有しているが、その方法はあまり直感的ではない。Python のコンテナから C++ コンテナへの変換は容易ではない。Python のコンテナを Boost.Python を使用して C++ 内でエミュレート(Python リファレンスマニュアルの「コンテナ型をエミュレートする」を見よ)するのは簡単ではない。C++ コンテナを Python へ変換する以前に考慮すべきことが多数ある。これには __len__ 、__getitem__ 、__setitem__ 、__delitem__ 、__iter__ および __contains__ メソッドに対するラッパ関数の実装が含まれる。
目的は、
添字アクセス可能な C++ コンテナの振る舞いを、Python コンテナの振る舞いに一致させる。
c[i] が変更可能であるといった、コンテナ要素のインデクス(
__getitem__)に対する既定の参照セマンティクスを提供する。要件は以下のとおり(mは非 const(可変)メンバ関数(メソッド))。val = c[i] c[i].m() val == c[i]
__getitem__から安全な参照を返す:後でコンテナに追加、コンテナから削除しても懸垂参照が発生しない(Python をクラッシュさせない)。スライスの添字をサポート。
適切な場合は Python のコンテナ引数(例:
list、tuple)を受け付ける。再定義可能なポリシークラスによる拡張性。
ほとんどの STL および STL スタイルの添字アクセス可能なコンテナに対する定義済みサポートを提供する。
Boost.Python の indexing インターフェイス
indexing_suite[ヘッダ <boost/python/indexing/indexing_suite.hpp>]
indexing_suite クラスは、Python に調和させる C++ コンテナを管理するための基底クラスである。目的は C++ コンテナの外観と振る舞いを Python コンテナのそれに一致させることである。このクラスは自動的に(Python リファレンスの「コンテナ型をエミュレートする」の)Python の特殊メソッドをラップする。
__len__(self)組み込み関数
lenを実装するために呼び出される。オブジェクトの長さ(0 以上の整数)を返さなければならない。また__nonzero__メソッドを定義せず__len__メソッドが 0 を返すオブジェクトは、論理値の文脈で偽として扱われる。__getitem__(self,key)self[key]の評価を実装するために呼び出される。シーケンス型では、受け取るキーは整数およびスライスオブジェクトでなければならない。負の添字に対する特殊な解釈(クラスがシーケンス型をエミュレートする場合)は__getitem__メソッドの仕事であることに注意していただきたい。keyが不適な型な場合はTypeErrorを送出し、値が(負の値に対する特殊な解釈の後)シーケンスの添字の集合外である場合はIndexErrorを送出しなければならない。注意:シーケンスの終了を適切に検出するため、forループは不正な添字に対してIndexErrorが送出することを想定している。__setitem__(self,key,value)self[key]への代入を実装するために呼び出される。注意すべき点は__getitem__と同じである。このメソッドは、マップ型についてはオブジェクトがキーに対する値の変更をサポートするか新しいキーを追加可能な場合、シーケンス型については要素が置換可能な場合のみ実装すべきである。不適なkey値に対しては__getitem__メソッドと同様の例外を送出しなければならない。__delitem__(self,key)self[key]の削除を実装するために呼び出される。注意すべき点は__getitem__と同じである。このメソッドは、マップ型についてはオブジェクトがキーの削除をサポートする場合、シーケンス型については要素をシーケンスから削除可能な場合のみ実装すべきである。不適なkey値に対しては__getitem__メソッドと同様の例外を送出しなければならない。__iter__(self)このメソッドは、コンテナに対してイテレータが要求されたときに呼び出される。このメソッドは、コンテナ内のすべてのオブジェクトを走査する新しいイテレータオブジェクトを返さなければならない。マップ型については、コンテナのキーを走査しなければならず、
iterkeysメソッドとしても利用可能でなければならない。イテレータオブジェクトもまたこのメソッドを実装する必要があり、自分自身を返さなければならない。イテレータオブジェクトの詳細については、Python ライブラリリファレンスの「イテレータ型」を見よ。
__contains__(self,item)メンバ関係テスト操作を実装するために呼び出される。
self内にitemがあれば真を、そうでなければ偽を返さなければならない。マップ型オブジェクトについては、値やキー・値の組ではなくキーを対象とすべきである。
indexing_suite の派生クラス
indexing_suite はそのままで使用することを意図していない。indexing_suite の派生クラスにより 2 、3 のポリシー関数を提供しなければならない。しかしながら、標準的な添字アクセス可能な STL コンテナのための indexing_suite 派生クラス群が提供されている。ほとんどの場合、単に定義済みのクラス群を使用すればよい。場合によっては必要に応じて定義済みクラスを改良してもよい。
vector_indexing_suite[ヘッダ <boost/python/indexing/vector_indexing_suite.hpp>]
vector_indexing_suite クラスは、std::vector クラス(および std::vector スタイルのクラス(例:std::vector のインターフェイスを持つクラス))をラップするために設計された定義済みの indexing_suite 派生クラスである。indexing_suite が要求するポリシーをすべて提供する。
class X {...};
...
class_<std::vector<X> >("XVec")
.def(vector_indexing_suite<std::vector<X> >())
;
XVec は完全な Python コンテナとなる(完全な例と Python のテストも見よ)。
map_indexing_suite[ヘッダ <boost/python/indexing/map_indexing_suite.hpp>]
map_indexing_suite クラスは、std::map クラス(および std::map スタイルのクラス(例:std::map のインターフェイスを持つクラス))をラップするために設計された定義済みの indexing_suite 派生クラスである。indexing_suite が要求するポリシーをすべて提供する。
class X {...};
...
class_<std::map<X> >("XMap")
.def(map_indexing_suite<std::map<X> >())
;
既定では添字アクセスした要素はプロキシで返される。NoProxy テンプレート引数で true を与えるとこれは無効化できる。XMap は完全な Python コンテナとなる(完全な例と Python のテストも見よ)。
indexing_suite クラス
-
template<class Container, class DerivedPolicies, bool NoProxy = false, bool NoSlice = false, class Data = typename Container::value_type, class Index = typename Container::size_type, class Key = typename Container::value_type>
class indexing_suite : unspecified - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
DerivedPolicies --
ポリシーフックを提供する派生クラス群。以下の DerivedPolicies を見よ。
- 要件
indexing_suiteの派生クラス
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxyテンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
NoSlice --
スライスを許可しない。
- 要件
論理値
- 既定
false
Data --
コンテナのデータ型。
- 既定
Container::value_type
Index --
コンテナの添字型。
- 既定
Container::size_type
Key --
コンテナのキー型。
- 既定
Container::value_type
template < class Container , class DerivedPolicies , bool NoProxy = false , bool NoSlice = false , class Data = typename Container::value_type , class Index = typename Container::size_type , class Key = typename Container::value_type > class indexing_suite : unspecified { public: indexing_suite(); // デフォルトコンストラクタ }
DerivedPolicies
派生クラスは indexing_suite が必要なフックを提供する。
data_type&
get_item(Container& container, index_type i);
static object
get_slice(Container& container, index_type from, index_type to);
static void
set_item(Container& container, index_type i, data_type const& v);
static void
set_slice(
Container& container, index_type from,
index_type to, data_type const& v
);
template <class Iter>
static void
set_slice(Container& container, index_type from,
index_type to, Iter first, Iter last
);
static void
delete_item(Container& container, index_type i);
static void
delete_slice(Container& container, index_type from, index_type to);
static size_t
size(Container& container);
template <class T>
static bool
contains(Container& container, T const& val);
static index_type
convert_index(Container& container, PyObject* i);
static index_type
adjust_index(index_type current, index_type from,
index_type to, size_type len
);
これらのポリシーの大部分は自己説明的であるが、convert_index と adjust_index は少し説明が必要である。
convert_index は Python の添字をコンテナが処理可能な C++ の添字に変換する。例えば Python における負の添字は右から数え始める(例:C[-1] は C 内の最も右の要素を差す)。convert_index は C++ コンテナのために必要な変換を処理しなければならない(例:-1 は C.size() - 1 である)。convert_index はまた、添字の型(Python の動的型)を C++ コンテナが想定する実際の型に変換できなければならない。
コンテナが拡張か縮小すると、要素への添字はデータの移動に追従して調整しなければならない。例えば 5 要素から成るベクタの 0 番目(a)から 3 つの要素を削除すると、添字 4 は添字 1 となる。
[a][b][c][d][e] ---> [d][e]
^ ^
4 1
adjust_index の仕事は調整である。添字 current を与えると、この関数はコンテナにおける添字 from..to におけるデータを len 個の要素で置換したときの調整後の添字を返す。
vector_indexing_suite クラス
-
template<class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default>
class vector_indexing_suite : unspecified_base - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxyテンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
DerivedPolicies --
vector_indexing_suiteはさらに定義済みのポリシーに派生している可能性がある。CRTP(James Coplien の「奇妙に再帰したテンプレートパターン」、C++ レポート、1995 年 2 月)を介した静的な多態により基底クラスindexing_suiteが最派生クラスのポリシー関数を呼び出せる。- 要件
indexing_suiteの派生クラス
template < class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default > class vector_indexing_suite : unspecified_base { public: typedef typename Container::value_type data_type; typedef typename Container::value_type key_type; typedef typename Container::size_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; data_type& get_item(Container& container, index_type i); static object get_slice(Container& container, index_type from, index_type to); static void set_item(Container& container, index_type i, data_type const& v); static void set_slice(Container& container, index_type from, index_type to, data_type const& v); template <class Iter> static void set_slice(Container& container, index_type from, index_type to, Iter first, Iter last); static void delete_item(Container& container, index_type i); static void delete_slice(Container& container, index_type from, index_type to); static size_t size(Container& container); static bool contains(Container& container, key_type const& key); static index_type convert_index(Container& container, PyObject* i); static index_type adjust_index(index_type current, index_type from, index_type to, size_type len); };
map_indexing_suite クラス
-
template<class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default>
class map_indexing_suite : unspecified_base - テンプレートパラメータ
Container --
Python に対してラップするコンテナ型。
- 要件
クラス型
NoProxy --
既定では添字アクセスした要素は Python の参照のセマンティクスを持ち、プロキシにより返される。これは
NoProxyテンプレート引数に真を与えることで無効化できる。- 要件
論理値
- 既定
false
DerivedPolicies --
map_indexing_suiteはさらに定義済みのポリシーに派生している可能性がある。CRTP(James Coplien の「奇妙に再帰したテンプレートパターン」、C++ レポート、1995 年 2 月)を介した静的な多態により基底クラスindexing_suiteが最派生クラスのポリシー関数を呼び出せる。- 要件
indexing_suiteの派生クラス
template < class Container, bool NoProxy = false, class DerivedPolicies = unspecified_default > class map_indexing_suite : unspecified_base { public: typedef typename Container::value_type value_type; typedef typename Container::value_type::second_type data_type; typedef typename Container::key_type key_type; typedef typename Container::key_type index_type; typedef typename Container::size_type size_type; typedef typename Container::difference_type difference_type; static data_type& get_item(Container& container, index_type i); static void set_item(Container& container, index_type i, data_type const& v); static void delete_item(Container& container, index_type i); static size_t size(Container& container); static bool contains(Container& container, key_type const& key); static bool compare_index(Container& container, index_type a, index_type b); static index_type convert_index(Container& container, PyObject* i); };