Skip to content

Instantly share code, notes, and snippets.

@m-ou-se
Created March 1, 2014 15:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m-ou-se/9291825 to your computer and use it in GitHub Desktop.
Save m-ou-se/9291825 to your computer and use it in GitHub Desktop.
Peeking Idea
class input {
// ...
/// Read the next character, but put it back.
/**
* \warning peek() does not work like std::istream::peek().
* This function will actually take the next character from
* the stream, and the object returned by peek() will put it back
* when it is destroyed, unless take() was called on that object.
* This means, when correctly used, you can peek more than just one
* character. If you want to peek a lot, consider using 'start_peeking'.
*/
peeked_char peek() {
return {this, get()};
}
/// Start peeking characters.
/**
* Returns an object on which you can call get() with the same
* effect as calling get() on this \ref input object, except
* that when the object is destroyed, all of the characters obtained
* through it (limited to the ones since the last call to take(), if
* any), will be put back.
*/
peeker start_peeking() {
return this;
}
protected:
class peeked_char {
private:
input * input_ = nullptr;
char character;
peeked_char(input * i, char c) : character(c), input_(i) {}
friend class input;
public:
peeked_char(peeked_char const &) = delete;
peeked_char & operator = (peeked_char const &) = delete;
peeked_char(peeked_char && o) { *this = std::move(o); }
peeked_char & operator = (peeked_char && o) {
character = o.character;
input_ = o.input_;
o.input_ = nullptr;
return *this;
}
char take() {
input_ = 0;
return character;
}
~peeked_char() {
if (input_) input_->output_buffer_.push_back(*this);
}
};
class peeker {
private:
input * input_;
std::vector<char> buffer_;
peeker(input * i) : input_(i) {}
friend class input;
public:
peeker(peeker const &) = delete;
peeker & operator = (peeker const &) = delete;
peeker(peeker && o) { *this = std::move(o); }
peeker & operator = (peeker && o) {
input_ = o.input_;
buffer_ = std::move(o.buffer_);
o.buffer_.clear();
return *this;
}
char get() {
auto c = input_->get();
buffer_.push_back(c);
return c;
}
void take() {
buffer_.clear();
}
~peeker() {
auto & b = input_->output_buffer_;
b.insert(b.end(), buffer_.rbegin(), buffer_.rend());
}
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment