Ragelを使う場合、たいていはイテレータをぽんと渡すことができる。ただし、Scannerを利用すると、イテレータを初期化するために0を代入する(まあ、元々対象としていたのはイテレータではなくポインタだから)。
というわけで、イテレータをラップして0を代入できるようにしよう(ちなみにRagelのソースコード変更するほうが楽だった)。要件を整理すると、Ragelが要求するのは、
というわけで、ラップされるイテレータの要件はBidirectional Iteratorとなる。完全なRandom Access Iteratorを作るためにはb - aが必要で、b - aはBidirectional Iteratorから作れない(作れないよね?)けれど、a + nとa - nに限定すればstd::advanceで作れる。
実装にboost::iterator_facadeを使った。boost::bidirectional_traversal_tagを指定したので、ラップするイテレータはBidirectional Iteratorである(と、名乗っている)。だけど、advanceを定義しておけば問題なし、iterator_categoryを気にしないRagelがa + nやa - nという構文を使っても、ちゃんとよきにはからってくれる。
さすが!
【追記】下記のコードは、ラップされるイテレータがRandom Access Iteratorの場合もBidirectional Iteratorを名乗るので、効率が悪くなる場合があるかもしれない。そのうち、真面目にメタるかも。
【追記2】効率が悪くなる(というか遅くなる)例としては、std::distance(begin, end)を呼び出した場合なんか。手元のstd::basic_string(iterator, iterator)の実装では、std::distanceを使って文字数をカウントしてる。
【追記3】b - aが計算できないのは、aとbの順序付けができないからだったはず。逆にb >= aが自明であればもちろん計算できる。
【追記4】ラップされるイテレータのカテゴリをそのまま名乗ることにしてみたコードをおしりに貼った。念のため、SFINAEしといた。
【改訂版】
というわけで、イテレータをラップして0を代入できるようにしよう(ちなみにRagelのソースコード変更するほうが楽だった)。要件を整理すると、Ragelが要求するのは、
- Bidirectional Iterator (N3242 P.823)
- a + n (N3242 P.824)
- a - n (N3242 P.824)
- a = 0
というわけで、ラップされるイテレータの要件はBidirectional Iteratorとなる。完全なRandom Access Iteratorを作るためにはb - aが必要で、b - aはBidirectional Iteratorから作れない(作れないよね?)けれど、a + nとa - nに限定すればstd::advanceで作れる。
実装にboost::iterator_facadeを使った。boost::bidirectional_traversal_tagを指定したので、ラップするイテレータはBidirectional Iteratorである(と、名乗っている)。だけど、advanceを定義しておけば問題なし、iterator_categoryを気にしないRagelがa + nやa - nという構文を使っても、ちゃんとよきにはからってくれる。
さすが!
【追記】下記のコードは、ラップされるイテレータがRandom Access Iteratorの場合もBidirectional Iteratorを名乗るので、効率が悪くなる場合があるかもしれない。そのうち、真面目にメタるかも。
【追記2】効率が悪くなる(というか遅くなる)例としては、std::distance(begin, end)を呼び出した場合なんか。手元のstd::basic_string(iterator, iterator)の実装では、std::distanceを使って文字数をカウントしてる。
【追記3】b - aが計算できないのは、aとbの順序付けができないからだったはず。逆にb >= aが自明であればもちろん計算できる。
【追記4】ラップされるイテレータのカテゴリをそのまま名乗ることにしてみたコードをおしりに貼った。念のため、SFINAEしといた。
template <typename T, typename = void> class scanner_iterator; template <typename T> class scanner_iterator< T, typename std::enable_if< std::is_base_of< std::bidirectional_iterator_tag, typename std::iterator_traits<T>::iterator_category >::value >::type > : public boost::iterator_facade< scanner_iterator<T>, typename std::iterator_traits<T>::value_type, typename boost::bidirectional_traversal_tag, typename std::iterator_traits<T>::reference, typename std::iterator_traits<T>::difference_type > { friend class boost::iterator_core_access; public: explicit scanner_iterator() : iterator_() {} explicit scanner_iterator(T const& iterator) : iterator_(iterator) {} // ragel scanner requests semantics (x = 0) scanner_iterator& operator=(int rhs) { BOOST_ASSERT(rhs == 0); iterator_ = T(); return *this; } private: T iterator_; typename std::iterator_traits<T>::reference dereference() const { return *iterator_; } bool equal(scanner_iterator const& rhs) const { return iterator_ == rhs.iterator_; } void increment() { ++iterator_; } void decrement() { --iterator_; } // ragel scanner requests semantics (x + n) and (x - n) void advance(typename std::iterator_traits<T>::difference_type n) { std::advance(iterator_, n); } };
【改訂版】
template <typename T, typename = void> class scanner_iterator; template <typename T> class scanner_iterator< T, typename std::enable_if< std::is_base_of< std::bidirectional_iterator_tag, typename std::iterator_traits<T>::iterator_category >::value >::type > : public boost::iterator_facade< scanner_iterator<T>, typename std::iterator_traits<T>::value_type, typename std::iterator_traits<T>::iterator_category, typename std::iterator_traits<T>::reference, typename std::iterator_traits<T>::difference_type > { friend class boost::iterator_core_access; public: explicit scanner_iterator() : iterator_() {} explicit scanner_iterator(T const& iterator) : iterator_(iterator) {} // ragel scanner request semantics (x = 0) scanner_iterator& operator=(int rhs) { BOOST_ASSERT(rhs == 0); iterator_ = T(); return *this; } private: T iterator_; typename std::iterator_traits<T>::reference dereference() const { return *iterator_; } bool equal(scanner_iterator const& rhs) const { return iterator_ == rhs.iterator_; } void increment() { ++iterator_; } void decrement() { --iterator_; } // ragel scanner request semantics (x + n) and (x - n) void advance(typename std::iterator_traits<T>::difference_type n) { std::advance(iterator_, n); } typename std::iterator_traits<T>::difference_type distance_to( scanner_iterator const& rhs, typename std::enable_if< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits<T>::iterator_category >::value >* = 0) const { return std::distance(iterator_, rhs.iterator_); } };
このページへのコメント
3tNJPR <a href="http://kkycnsoteybz.com/">kkycnsoteybz</a>, [url=http://ucjqevophbay.com/]ucjqevophbay[/url], [link=http://rhzkrwuowjcg.com/]rhzkrwuowjcg[/link], http://duwgjfpzfivy.com/