about summary refs log tree commit diff
diff options
context:
space:
mode:
authorShea Levy <shea@shealevy.com>2016-11-17T15·10-0500
committerShea Levy <shea@shealevy.com>2016-11-17T15·10-0500
commit0d2ebb4373e509521f27a6e8f16bfd39d05b2188 (patch)
tree4565d5bdfe814fd7b07797b8cc905cefc172490e
parent3f4d3f8a1a178c4d7a80d20b3bac9889bac49f9c (diff)
istringstream_nocopy: Implement in a standards-compliant way
Fixes #1135.
-rw-r--r--src/libutil/util.hh44
1 files changed, 40 insertions, 4 deletions
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index a8f6f99b957f..f38c2bb7c154 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -435,14 +435,50 @@ void callSuccess(
    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. */
-struct istringstream_nocopy : public std::stringstream
+class istringbuf_nocopy : public std::streambuf
 {
-    istringstream_nocopy(const std::string & s)
+    const std::string & s;
+    std::streamsize off;
+public:
+    istringbuf_nocopy(const std::string & s) : s{s}, off{0}
+    {
+    }
+
+private:
+    int_type underflow()
+    {
+      if (off == s.size())
+          return traits_type::eof();
+      return traits_type::to_int_type(s[off]);
+    }
+
+    int_type uflow()
+    {
+        if (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]);
+    }
+
+    std::streamsize showmanyc()
     {
-        rdbuf()->pubsetbuf(
-            (char *) s.data(), s.size());
+        return s.size() - off;
     }
 };
 
 
+struct istringstream_nocopy : public std::istream
+{
+    istringbuf_nocopy buf;
+    istringstream_nocopy(const std::string & s) : std::istream(&buf), buf(s) {};
+};
+
+
 }