#ifndef LIBWCCL_SENTENCECONTEXT_H #define LIBWCCL_SENTENCECONTEXT_H #include <libcorpus2/sentence.h> #include <libwccl/values/position.h> #include <boost/shared_ptr.hpp> namespace Wccl { /** * A wrapper for a Corpus2 Sentence that adds a "current position" * and several convenience functions. * * Copying contexts is cheap and safe since the sentence is kept through * a shared pointer, use duplicate() or clone() to get a copy with a separate * underlying sentence (which is slower). */ class SentenceContext { public: /// Constructor, wraps the Sentence and sets position to 0 explicit SentenceContext(const boost::shared_ptr<Corpus2::Sentence>& s); /// Returns a copy of this with a cloned underlyiong sentence SentenceContext duplicate() const; /// Cloning -- clones the underlying sentence as well SentenceContext* clone() const; /// Underlying sentence accessor Corpus2::Sentence& get_sentence() { return *sentence_; } /// Underlying sentence accessor, const const Corpus2::Sentence& get_sentence() const { return *sentence_; } /// Shorthand to get_sentence().size() int size() const { return sentence_->size(); } /// Position accessor int get_position() const { return position_; } /// Checks if the current position is valid (within the sentence bounds) bool is_current_inside() const { return is_inside(position_); } /// Checks if the the given absolute position is valid (in sentence bounds) bool is_inside(int abs_pos) const { return abs_pos >= 0 && abs_pos < size(); } /// Checks if the the given position is valid (in sentence bounds) bool is_inside(const Position& pos) const { return is_inside(get_abs_position(pos)); } /// Checks if the the given absolute position is outside sentence, including nowhere bool is_outside(int abs_pos) const { return !is_inside(abs_pos); } /// Checks if the the given position is outside sentence, including nowhere bool is_outside(const Position& pos) const { return !is_inside(get_abs_position(pos)); } /** * Checks if range is valid, i.e. non-empty and not outside of sentence, * and at the same time finds absolute values of passed Positions * @param left Position specyfing left extreme of the range * @param right Position specyfing right extreme of the range * @param abs_left reference to int value that will hold absolute * value for left position * @param abs_right reference to int value that will hold absolute * value for right position * @returns true if range is valid; in this case abs_left and abs_right * are set to absolute positions values for left and right Position. * False is returned otherwise; in this case abs_left and abs_right * are set to Nowhere */ bool validate_range( const Position& left, const Position& right, int& abs_left, int& abs_right) const; /// Position setter void set_position(int new_position) { position_ = new_position; } /// Position advance shorthand void advance() { ++position_; } /// Reste position to point to the first token void goto_start() { position_ = 0; } /// Token access convenience function - const. /// Will return NULL if the passed position is not valid in this Sentence const Corpus2::Token* at(int abs_pos) const { if (is_inside(abs_pos)) { return get_sentence()[abs_pos]; } else { return NULL; } } /// Token access const function overload that takes a Position object const Corpus2::Token* at(const Position& position) const { return at(get_abs_position(position)); } /// Token access convenience function. /// Will return NULL if the passed position is not valid in this Sentence Corpus2::Token* at(int abs_pos) { if (is_inside(abs_pos)) { return get_sentence()[abs_pos]; } else { return NULL; } } /// Token access function overload that takes a Position object Corpus2::Token* at(const Position& position) { return at(get_abs_position(position)); } /// Current token access shorthand, const. @see at const Corpus2::Token* current() const { return at(position_); } /// Current token access shorthand. @see at Corpus2::Token* current() { return at(position_); } int get_abs_position(const Position& position) const; int get_rel_position(const Position& position) const; int translate_special_position(int pos) const { switch (pos) { case Position::Begin: return 0; case Position::End: return sentence_->size() - 1; case Position::Nowhere: return Position::Nowhere; default: return position_ + pos; } } private: /// The wrapped sentence boost::shared_ptr<Corpus2::Sentence> sentence_; /// Current position in the sentence int position_; }; inline bool SentenceContext::validate_range( const Position& left, const Position& right, int& abs_left, int& abs_right) const { abs_left = get_abs_position(left); if (abs_left == Position::Nowhere) { abs_right = Position::Nowhere; return false; } abs_right = get_abs_position(right); if (abs_right == Position::Nowhere) { abs_left = Position::Nowhere; return false; } // Trim range to sentence boundaries if (abs_left < 0) { abs_left = 0; } if (abs_right >= size()) { abs_right = size() - 1; } // is range valid? this covers "crossed" range, an empty sentence, // and range outside boundaries of sentence if (abs_left > abs_right) { abs_left = Position::Nowhere; abs_right = Position::Nowhere; return false; } return true; } // TODO ConstSentenceContext ? } /* end ns Wccl */ #endif // LIBWCCL_SENTENCECONTEXT_H