From 4fc30922cf00d79bd603ac46255fa73a3c2ee565 Mon Sep 17 00:00:00 2001 From: Shea Levy Date: Mon, 6 Mar 2017 13:03:02 -0500 Subject: [PATCH] istringstream_nocopy: Implement in a standards-compliant way. Fixes the problem mentioned in e6a61b8da788efbbbb0eb690c49434b6b5fc9741 See #1135 --- src/libstore/derivations.cc | 2 +- src/libstore/s3-binary-cache-store.cc | 13 ---- src/libutil/hash.cc | 2 +- src/libutil/util.hh | 87 +++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index ce1ac7d33..38a87240c 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -152,7 +152,7 @@ static StringSet parseStrings(std::istream & str, bool arePaths) static Derivation parseDerivation(const string & s) { Derivation drv; - std::istringstream str(s); + istringstream_nocopy str(s); expect(str, "Derive(["); /* Parse the list of outputs. */ diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc index 041c68c68..1121b4d4c 100644 --- a/src/libstore/s3-binary-cache-store.cc +++ b/src/libstore/s3-binary-cache-store.cc @@ -117,17 +117,6 @@ S3Helper::DownloadResult S3Helper::getObject( return res; } -#if __linux__ - -struct istringstream_nocopy : public std::stringstream -{ - istringstream_nocopy(const std::string & s) - { - rdbuf()->pubsetbuf( - (char *) s.data(), s.size()); - } -}; - struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore { std::string bucketName; @@ -313,8 +302,6 @@ static RegisterStoreImplementation regStore([]( return store; }); -#endif - } #endif diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index f447c80c5..a8bbcf8c1 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -104,7 +104,7 @@ Hash parseHash(HashType ht, const string & s) string s2(s, i * 2, 2); if (!isxdigit(s2[0]) || !isxdigit(s2[1])) throw BadHash(format("invalid hash ‘%1%’") % s); - std::istringstream str(s2); + istringstream_nocopy str(s2); int n; str >> std::hex >> n; hash.hash[i] = n; diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 2950f7daa..7cb3e68b9 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -449,4 +449,91 @@ struct ReceiveInterrupts }; +template , class Allocator = std::allocator> +class basic_istringbuf_nocopy : public std::basic_streambuf +{ +public: + typedef std::basic_string string_type; + + typedef typename std::basic_streambuf::off_type off_type; + + typedef typename std::basic_streambuf::pos_type pos_type; + + typedef typename std::basic_streambuf::int_type int_type; + + typedef typename std::basic_streambuf::traits_type traits_type; + +private: + const string_type & s; + + off_type off; + +public: + basic_istringbuf_nocopy(const string_type & s) : s{s}, off{0} + { + } + +private: + pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) + { + if (which & std::ios_base::in) { + this->off = dir == std::ios_base::beg + ? off + : (dir == std::ios_base::end + ? s.size() + off + : this->off + off); + } + return pos_type(this->off); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode which) + { + return seekoff(pos, std::ios_base::beg, which); + } + + std::streamsize showmanyc() + { + return s.size() - off; + } + + int_type underflow() + { + if (typename string_type::size_type(off) == s.size()) + return traits_type::eof(); + return traits_type::to_int_type(s[off]); + } + + int_type uflow() + { + if (typename string_type::size_type(off) == s.size()) + return traits_type::eof(); + return traits_type::to_int_type(s[off++]); + } + + int_type pbackfail(int_type ch) + { + if (off == 0 || (ch != traits_type::eof() && ch != s[off - 1])) + return traits_type::eof(); + + return traits_type::to_int_type(s[--off]); + } + +}; + +template , class Allocator = std::allocator> +class basic_istringstream_nocopy : public std::basic_iostream +{ + typedef basic_istringbuf_nocopy buf_type; + buf_type buf; +public: + basic_istringstream_nocopy(const typename buf_type::string_type & s) : + std::basic_iostream(&buf), buf(s) {}; +}; + +/* A variant of std::istringstream that doesn't its string + argument. This is useful for large strings. The caller must ensure + that the string object is not destroyed while it's referenced by + this object. */ +typedef basic_istringstream_nocopy istringstream_nocopy; + }