optional_iterator

bjam_grammarをテストしていて、string_listのバグを見つけました。

hamigaki::bjam::string_list ls;
ls.begin() == ls.end(); // VC8のデバッグモードだとassert落ち

原因は、string_listが空の場合、begin()もend()も空(どのvectorの要素も指していない)のvector<string>::iteratorを返していて、これを比較に使っているためです。
とはいえ、これだけのために空のvectorをnewしておくのは無駄なので、反復子に手を加えることにしました。
<hamigaki/iterator/optional_iterator.hpp>

#include <boost/iterator/iterator_adaptor.hpp>

namespace hamigaki
{

template<class Iterator>
class optional_iterator
    : public boost::iterator_adaptor<
        optional_iterator<Iterator>,
        Iterator
    >
{
    friend class boost::iterator_core_access;

private:
    typedef optional_iterator<Iterator> self_type;
    typedef typename self_type::iterator_adaptor_ base_type;

public:
    optional_iterator() : valid_(false)
    {
    }

    optional_iterator(Iterator it) : base_type(it), valid_(true)
    {
    }

private:
    bool valid_;

    bool equal(const self_type& rhs) const
    {
        if (valid_)
        {
            if (rhs.valid_)
                return this->base() == rhs.base();
            else
                return false;
        }
        else
            return !rhs.valid_;
    }
};

} // namespace hamigaki

デフォルトコンストラクタで初期化されたoptional_iteratorは、どの要素も指していませんが、equal()で比較基準を変更することで、互いに等しくなるようになっています。
string_listの反復子はこれでラップするようにしました。