/* * Copyright (c) 2017 Jaroslav Jindrak * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LIBCPP_ISTREAM #define LIBCPP_ISTREAM #include #include #include #include #include #include namespace std { /** * 27.7.2.1, class template basic_stream: */ template class basic_istream: virtual public basic_ios { public: using traits_type = Traits; using char_type = Char; using int_type = typename traits_type::int_type; using pos_type = typename traits_type::pos_type; using off_type = typename traits_type::off_type; /** * 27.7.2.1.1, constructor/destructor: */ explicit basic_istream(basic_streambuf* sb) : gcount_{0} { printf("ISTREAM\n"); basic_ios::init(sb); } virtual ~basic_istream() { /* DUMMY BODY */ } /** * 27.7.2.1.3, prefix/suffix: */ class sentry { public: explicit sentry(basic_istream& is, bool noskipws = false) : ok_{false} { if (!is.good()) is.setstate(ios_base::failbit); else { if (is.tie()) is.tie()->flush(); if (!noskipws && ((is.flags() & ios_base::skipws) != 0)) { const auto& ct = use_facet>(is.getloc()); while (true) { auto i = is.rdbuf()->sgetc(); if (Traits::eq_int_type(i, Traits::eof())) { is.setstate(ios_base::failbit | ios_base::eofbit); break; } auto c = Traits::to_char_type(i); if (!ct.is(c, ct.space)) break; else is.rdbuf()->sbumpc(); } } } if (is.good()) ok_ = true; } ~sentry() = default; explicit operator bool() const { return ok_; } sentry(const sentry&) = delete; sentry& operator=(const sentry&) = delete; private: using traits_type = Traits; bool ok_; }; /** * 27.7.2.2, formatted input: */ basic_istream& operator>>( basic_istream& (*pf)(basic_istream&) ) { return pf(*this); } basic_istream& operator>>( basic_ios& (*pf)(basic_ios&) ) { pf(*this); return *this; } basic_istream& operator>>( ios_base& (*pf)(ios_base&) ) { pf(*this); return *this; } basic_istream& operator>>(bool& x) { // TODO: implement } basic_istream& operator>>(short& x) { // TODO: implement } basic_istream& operator>>(unsigned short& x) { // TODO: implement } basic_istream& operator>>(int& x) { // TODO: implement } basic_istream& operator>>(unsigned int& x) { // TODO: implement } basic_istream& operator>>(long& x) { // TODO: implement } basic_istream& operator>>(unsigned long& x) { // TODO: implement } basic_istream& operator>>(long long& x) { // TODO: implement } basic_istream& operator>>(unsigned long long& x) { // TODO: implement } basic_istream& operator>>(float& x) { // TODO: implement } basic_istream& operator>>(double& x) { // TODO: implement } basic_istream& operator>>(long double& x) { // TODO: implement } basic_istream& operator>>(void*& p) { // TODO: implement } basic_istream& operator>>(basic_streambuf* sb) { // TODO: implement } /** * 27.7.2.3, unformatted input: * TODO: Once we have exceptions, implement * 27.7.2.3 paragraph 1. */ streamsize gcount() const { return gcount_; } int_type get() { gcount_ = 0; sentry sen{*this, true}; if (sen) { auto res = this->rdbuf()->sbumpc(); if (!traits_type::eq_int_type(res, traits_type::eof())) { gcount_ = 1; return res; } this->setstate(ios_base::failbit | ios_base::eofbit); } return traits_type::eof(); } basic_istream& get(char_type& c) { auto res = get(); if (res != traits_type::eof()) c = traits_type::to_char_type(res); return this; } basic_istream& get(char_type* s, streamsize n, char_type delim) { gcount_ = 0; sentry sen{*this, true}; if (sen && n > 0) { while(gcount_ < n - 1) { auto c = this->rdbuf()->sbumpc(); if (traits_type::eq_int_type(c, traits_type::eof())) { this->setstate(ios_base::eofbit); break; } s[gcount_++] = traits_type::to_char_type(c); auto peek = traits_type::to_char_type(this->rdbuf()->sgetc()); if (traits_type::eq(peek, delim)) break; } if (gcount_ == 0) this->setstate(ios_base::failbit); s[n] = char_type{}; } return *this; } basic_istream& get(char_type* s, streamsize n) { return get(s, n, this->widen('\n')); } basic_istream& get(basic_streambuf& sb) { get(sb, this->widen('\n')); } basic_istream& get(basic_streambuf& sb, char_type delim) { gcount_ = 0; sentry sen{*this, true}; if (sen) { while (true) { auto i = this->rdbuf()->sgetc(); if (traits_type::eq_int_type(i, traits_type::eof())) { this->setstate(ios_base::eofbit); break; } auto c = traits_type::to_char_type(i); if (traits_type::eq(c, delim)) break; auto insert_ret = sb.sputc(c); if (traits_type::eq_int_type(insert_ret, traits_type::eof())) break; this->rdbuf()->sbumpc(); ++gcount_; } if (gcount_ == 0) this->setstate(ios_base::failbit); } return *this; } basic_istream& getline(char_type* s, streamsize n) { return getline(s, n, this->widen('\n')); } basic_istream& getline(char_type* s, streamsize n, char_type delim) { gcount_ = 0; sentry sen{*this, true}; if (sen) { while (true) { // We have exactly specified order of checks, easier to do them in the body. auto c = this->rdbuf()->sbumpc(); if (traits_type::eq_int_type(c, traits_type::eof())) { this->setstate(ios_base::eofbit); break; } if (traits_type::eq_int_type(c, traits_type::to_int_type(delim))) break; if (n < 1 || gcount_ >= n - 1) { this->setstate(ios_base::failbit); break; } s[gcount_++] = traits_type::to_char_type(c); } if (gcount_ == 0) this->setstate(ios_base::failbit); if (n > 0) s[gcount_] = char_type{}; } return *this; } basic_istream& ignore(streamsize n = 1, int_type delim = traits_type::eof()) { sentry sen{*this, true}; if (sen) { streamsize i{}; while (n == numeric_limits::max() || i < n) { auto c = this->rdbuf()->sbumpc(); if (traits_type::eq_int_type(c, traits_type::eof())) { this->setstate(ios_base::eofbit); break; } if (traits_type::eq_int_type(c, delim)) break; } } } int_type peek() { sentry sen{*this, true}; if (!this->good()) return traits_type::eof(); else return this->rdbuf()->sgetc(); } basic_istream& read(char_type* s, streamsize n) { gcount_ = 0; sentry sen{*this, true}; if (!this->good()) { this->setstate(ios_base::failbit); return *this; } while (gcount_ < n) { auto c = this->rdbuf()->sbumpc(); if (traits_type::eq_int_type(c, traits_type::eof())) { this->setstate(ios_base::failbit | ios_base::eofbit); break; } s[gcount_++] = traits_type::to_char_type(c); } } streamsize readsome(char_type* s, streamsize n) { gcount_ = 0; sentry sen{*this, true}; if (!this->good()) { this->setstate(ios_base::failbit); return streamsize{}; } auto avail = this->rdbuf()->in_avail(); if (avail == -1) { this->setstate(ios_base::eofbit); return streamsize{}; } else if (avail > 0) { auto count = (avail < n ? avail : n); while (gcount_ < count) s[gcount_++] = traits_type::to_char_type(this->rdbuf()->sbumpc()); } return gcount_; } basic_istream& putback(char_type c) { clear(this->rdstate() & (~ios_base::eofbit)); gcount_ = 0; sentry sen{*this, true}; if (!this->good()) { this->setstate(ios_base::failbit); return *this; } if (this->rdbuf()) { auto ret = this->rdbuf()->sputbackc(c); if (traits_type::eq_int_type(ret, traits_type::eof())) this->setstate(ios_base::badbit); } else this->setstate(ios_base::badbit); return *this; } basic_istream& unget() { clear(this->rdstate() & (~ios_base::eofbit)); gcount_ = 0; sentry sen{*this, true}; if (!this->good()) { this->setstate(ios_base::failbit); return *this; } if (this->rdbuf()) { auto ret = this->rdbuf()->sungetc(); if (traits_type::eq_int_type(ret, traits_type::eof())) this->setstate(ios_base::badbit); } else this->setstate(ios_base::badbit); return *this; } int sync() { sentry s{*this, true}; if (this->rdbuf()) { auto ret = this->rdbuf()->pubsync(); if (ret == -1) { this->setstate(ios_base::badbit); return -1; } else return 0; } else return -1; } pos_type tellg() { sentry s{*this, true}; if (this->fail()) return pos_type(-1); else return this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in); } basic_istream& seekg(pos_type pos) { this->clear(this->rdstate() & (~ios_base::eofbit)); sentry sen{*this, true}; if (!this->fail()) this->rdbuf()->pubseekoff(pos, ios_base::in); else this->setstate(ios_base::failbit); return *this; } basic_istream& seekg(off_type off, ios_base::seekdir dir) { sentry sen{*this, true}; if (!this->fail()) this->rdbuf()->pubseekoff(off, dir, ios_base::in); else this->setstate(ios_base::failbit); return *this; } protected: streamsize gcount_; basic_istream(const basic_istream&) = delete; basic_istream(basic_istream&& rhs) { gcount_ = rhs.gcout_; basic_ios::move(rhs); rhs.gcount_ = 0; } /** * 27.7.2.1.2, assign/swap: */ basic_istream& operator=(const basic_istream& rhs) = delete; basic_istream& operator=(basic_istream&& rhs) { swap(rhs); return *this; } void swap(basic_istream& rhs) { basic_ios::swap(rhs); swap(gcount_, rhs.gcount_); } }; /** * 27.7.2.2.3, character extraction templates: */ template basic_istream& operator>>(basic_istream& is, Char& c) { // TODO: implement } template basic_istream& operator>>(basic_istream& is, unsigned char& c) { // TODO: implement } template basic_istream& operator>>(basic_istream& is, signed char& c) { // TODO: implement } template basic_istream& operator>>(basic_istream& is, Char* c) { // TODO: implement } template basic_istream& operator>>(basic_istream& is, unsigned char* c) { // TODO: implement } template basic_istream& operator>>(basic_istream& is, signed char* c) { // TODO: implement } /** * 27.7.2.4, standard basic_istream manipulators: */ template> basic_istream& ws(basic_istream& is) { using sentry = typename basic_istream::sentry; sentry sen{is, true}; if (sen) { const auto& ct = use_facet>(is.getloc()); while (true) { auto i = is.rdbuf()->sgetc(); if (Traits::eq_int_type(i, Traits::eof())) { is.setstate(ios_base::eofbit); break; } auto c = Traits::to_char_type(i); if (!ct.is(c, ct.space)) break; else is.rdbuf()->sbumpc(); } } return is; } using istream = basic_istream; using wistream = basic_istream; /** * 27.7.2.5, class template basic_iostream: */ template class basic_iostream; using iostream = basic_iostream; using wiostream = basic_iostream; /** * 27.7.2.6, rvalue stream extraction: */ template basic_istream& operator>>(basic_istream&& is, T& x) { is >> x; return is; } } #endif