summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2016-03-01 06:45:41 +1100
committer Vas Crabb <vas@vastheman.com>2016-03-01 06:52:36 +1100
commita830ea76270b7894a03922a172d58bfaefbc827f (patch)
tree01d929c08c8fa3e66285a3130004d4aa5d31e393 /src/lib
parentb2fc583ed75b19321849fcd4fec518e2b719294b (diff)
* Support *n conversion in stream_format/string_format
* Make stream_format return characters printed * Add iostreams with std::vector storage * Move to type-safe templates for logerror and popmessage * Remove now-unnecessary I64FMT from calls to logerror/popmessage * Put some lib/util stuff in util:: namespace * Some fixes to Japanese translation
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/util/corestr.h5
-rw-r--r--src/lib/util/options.cpp10
-rw-r--r--src/lib/util/strformat.h86
-rw-r--r--src/lib/util/vecstream.h362
4 files changed, 449 insertions, 14 deletions
diff --git a/src/lib/util/corestr.h b/src/lib/util/corestr.h
index 9d06b30c9f7..209cde389e1 100644
--- a/src/lib/util/corestr.h
+++ b/src/lib/util/corestr.h
@@ -15,6 +15,9 @@
#include "osdcore.h"
#include "strformat.h"
+
+#include <string>
+
#include <string.h>
@@ -63,8 +66,6 @@ char *core_i64_format(UINT64 value, UINT8 mindigits, bool is_octal);
char *core_i64_hex_format(UINT64 value, UINT8 mindigits);
char *core_i64_oct_format(UINT64 value, UINT8 mindigits);
-#include <string>
-
int strvprintf(std::string &str, const char *format, va_list args);
int strcatvprintf(std::string &str, const char *format, va_list args);
diff --git a/src/lib/util/options.cpp b/src/lib/util/options.cpp
index ccc6024c9f9..56bad147bcb 100644
--- a/src/lib/util/options.cpp
+++ b/src/lib/util/options.cpp
@@ -519,7 +519,7 @@ std::string core_options::output_ini(const core_options *diff) const
{
if (num_valid_headers++)
buffer << '\n';
- stream_format(buffer, "#\n# %s\n#\n", last_header);
+ util::stream_format(buffer, "#\n# %s\n#\n", last_header);
last_header = nullptr;
}
@@ -527,9 +527,9 @@ std::string core_options::output_ini(const core_options *diff) const
if (!is_unadorned)
{
if (strchr(value, ' ') != nullptr)
- stream_format(buffer, "%-25s \"%s\"\n", name, value);
+ util::stream_format(buffer, "%-25s \"%s\"\n", name, value);
else
- stream_format(buffer, "%-25s %s\n", name, value);
+ util::stream_format(buffer, "%-25s %s\n", name, value);
}
}
}
@@ -553,11 +553,11 @@ std::string core_options::output_help() const
{
// header: just print
if (curentry->is_header())
- stream_format(buffer, "\n#\n# %s\n#\n", curentry->description());
+ util::stream_format(buffer, "\n#\n# %s\n#\n", curentry->description());
// otherwise, output entries for all non-deprecated items
else if (curentry->description() != nullptr)
- stream_format(buffer, "-%-20s%s\n", curentry->name(), curentry->description());
+ util::stream_format(buffer, "-%-20s%s\n", curentry->name(), curentry->description());
}
return buffer.str();
}
diff --git a/src/lib/util/strformat.h b/src/lib/util/strformat.h
index 3bf95a5df29..96add0dfcca 100644
--- a/src/lib/util/strformat.h
+++ b/src/lib/util/strformat.h
@@ -91,6 +91,8 @@
widening or narrowing
- s/S: default stream output behaviour for argument
- p/P: cast any integer/char/bool/pointer/array to void const *
+ - n: store characters printed so far, produces no output, argument
+ must be pointer to type that std::streamoff is convertible to
- m: output of std::strerror(errno), no automatic widening or
narrowing, does not consume an argument
- %: literal %, field width applied, does not consume an argument
@@ -128,13 +130,13 @@
- Out-of-range argument/width/precision position
- Inappropriate type for parameterised width/precision
- Positional width/precision specifier not terminated with $
+ - Inappropriate type for n conversion
Some limitations have been described in passing. Major limitations
and bugs include:
- No automatic widening/narrowing support, so no simple way to
output wide characters/strings to narrow streams/strings and vice
versa.
- - No support for n conversion (store characters printed so far)
- Precision ignored for d/i/u/o/x/X conversions (should set minimum
digits to print).
- Precisoin for s/S conversion is only honoured for string-like
@@ -183,7 +185,7 @@
#include <type_traits>
#include <utility>
-
+namespace util {
namespace detail {
template <typename Character>
class format_chars
@@ -221,6 +223,7 @@ public:
l = Character('l'),
L = Character('L'),
m = Character('m'),
+ n = Character('n'),
o = Character('o'),
p = Character('p'),
s = Character('s'),
@@ -270,6 +273,7 @@ public:
l = L'l',
L = L'L',
m = L'm',
+ n = L'n',
o = L'o',
p = L'p',
s = L's',
@@ -320,6 +324,7 @@ public:
character, // c, C
string, // s, S
pointer, // p
+ tell, // n
strerror, // m
percent // %
};
@@ -389,6 +394,7 @@ public:
case conversion::character:
case conversion::string:
case conversion::pointer:
+ case conversion::tell:
case conversion::strerror:
case conversion::percent:
break;
@@ -839,6 +845,9 @@ public:
case format_helper::p:
flags.set_conversion(format_flags::conversion::pointer);
break;
+ case format_helper::n:
+ flags.set_conversion(format_flags::conversion::tell);
+ break;
case format_helper::m:
flags.set_conversion(format_flags::conversion::strerror);
break;
@@ -1256,6 +1265,39 @@ public:
}
};
+template <typename T>
+class format_store_integer
+{
+private:
+ template <typename U> struct is_non_const_ptr
+ { static constexpr bool value = std::is_pointer<U>::value && !std::is_const<std::remove_pointer_t<U> >::value; };
+ template <typename U> struct is_unsigned_ptr
+ { static constexpr bool value = std::is_pointer<U>::value && std::is_unsigned<std::remove_pointer_t<U> >::value; };
+ template <typename U> struct use_unsigned_cast
+ { static constexpr bool value = is_non_const_ptr<U>::value && is_unsigned_ptr<U>::value && std::is_convertible<std::make_unsigned_t<std::streamoff>, std::remove_pointer_t<U> >::value; };
+ template <typename U> struct use_signed_cast
+ { static constexpr bool value = is_non_const_ptr<U>::value && !use_unsigned_cast<U>::value && std::is_convertible<std::streamoff, std::remove_pointer_t<U> >::value; };
+ template <typename U> struct disable
+ { static constexpr bool value = !use_unsigned_cast<U>::value && !use_signed_cast<U>::value; };
+
+public:
+ template <typename U> static std::enable_if_t<use_unsigned_cast<U>::value, bool> apply(U const &value, std::streamoff data)
+ {
+ *value = std::remove_pointer_t<U>(std::make_unsigned_t<std::streamoff>(data));
+ return true;
+ }
+ template <typename U> static std::enable_if_t<use_signed_cast<U>::value, bool> apply(U const &value, std::streamoff data)
+ {
+ *value = std::remove_pointer_t<U>(std::make_signed_t<std::streamoff>(data));
+ return true;
+ }
+ template <typename U> static std::enable_if_t<disable<U>::value, bool> apply(U const &value, std::streamoff data)
+ {
+ assert(false); // inappropriate type for storing characters written so far
+ return false;
+ }
+};
+
template <typename Stream>
class format_argument
{
@@ -1264,6 +1306,7 @@ public:
: m_value(nullptr)
, m_output_function(nullptr)
, m_make_integer_function(nullptr)
+ , m_store_integer_function(nullptr)
{
}
@@ -1272,15 +1315,18 @@ public:
: m_value(reinterpret_cast<void const *>(&value))
, m_output_function(&static_output<T>)
, m_make_integer_function(&static_make_integer<T>)
+ , m_store_integer_function(&static_store_integer<T>)
{
}
void output(Stream &str, format_flags const &flags) const { m_output_function(str, flags, m_value); }
bool make_integer(int &result) const { return m_make_integer_function(m_value, result); }
+ void store_integer(std::streamoff data) const { m_store_integer_function(m_value, data); }
private:
typedef void (*output_function)(Stream &str, format_flags const &flags, void const *value);
typedef bool (*make_integer_function)(void const *value, int &result);
+ typedef void (*store_integer_function)(void const *value, std::streamoff data);
template <typename T> static void static_output(Stream &str, format_flags const &flags, void const *value)
{
@@ -1292,9 +1338,15 @@ private:
return format_make_integer<T>::apply(*reinterpret_cast<T const *>(value), result);
}
+ template <typename T> static void static_store_integer(void const *value, std::streamoff data)
+ {
+ format_store_integer<T>::apply(*reinterpret_cast<T const *>(value), data);
+ }
+
void const *m_value;
output_function m_output_function;
make_integer_function m_make_integer_function;
+ store_integer_function m_store_integer_function;
};
template <typename Stream, typename... Params>
@@ -1304,7 +1356,7 @@ inline std::array<format_argument<Stream>, sizeof...(Params)> make_format_argume
}
template <typename Stream, typename Format, std::size_t Count>
-void stream_format(Stream &str, Format const &fmt, std::array<format_argument<Stream>, Count> const &args)
+typename Stream::off_type stream_format(Stream &str, Format const &fmt, std::array<format_argument<Stream>, Count> const &args)
{
typedef format_helper<std::remove_reference_t<Format> > format_helper;
typedef typename format_helper::iterator iterator;
@@ -1334,7 +1386,8 @@ void stream_format(Stream &str, Format const &fmt, std::array<format_argument<St
std::streamsize m_width;
};
- stream_preserver preserver(str);
+ typename Stream::pos_type const begin(str.tellp());
+ stream_preserver const preserver(str);
int next_pos(1);
iterator start = format_helper::begin(fmt);
for (iterator it = start; !format_helper::at_end(fmt, start); )
@@ -1415,20 +1468,35 @@ void stream_format(Stream &str, Format const &fmt, std::array<format_argument<St
assert(args.size() >= unsigned(arg_pos));
if ((0 >= arg_pos) || (args.size() < unsigned(arg_pos)))
continue;
- args[arg_pos - 1].output(str, flags);
+ if (format_flags::conversion::tell == flags.get_conversion())
+ {
+ typename Stream::pos_type const current(str.tellp());
+ args[arg_pos - 1].store_integer(
+ ((typename Stream::pos_type(-1) == begin) || (typename Stream::pos_type(-1) == current))
+ ? typename Stream::off_type(-1)
+ : (current - begin));
+ }
+ else
+ {
+ args[arg_pos - 1].output(str, flags);
+ }
start = it;
}
}
}
+ typename Stream::pos_type const end(str.tellp());
+ return ((typename Stream::pos_type(-1) == begin) || (typename Stream::pos_type(-1) == end))
+ ? typename Stream::off_type(-1)
+ : (end - begin);
}
} // namespace detail
template <typename Stream, typename Format, typename... Params>
-inline void stream_format(Stream &str, Format const &fmt, Params &&... args)
+inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args)
{
auto const arg_pack(detail::make_format_arguments<Stream>(std::forward<Params>(args)...));
- detail::stream_format(str, fmt, arg_pack);
+ return detail::stream_format(str, fmt, arg_pack);
}
template <typename String = std::string, typename Format, typename... Params>
@@ -1450,4 +1518,8 @@ inline String string_format(std::locale const &locale, Format const &fmt, Params
return str.str();
};
+} // namespace util
+
+using util::string_format;
+
#endif // __MAME_UTIL_STRFORMAT_H__
diff --git a/src/lib/util/vecstream.h b/src/lib/util/vecstream.h
new file mode 100644
index 00000000000..9c7c5d5b4e0
--- /dev/null
+++ b/src/lib/util/vecstream.h
@@ -0,0 +1,362 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ vecstream.h
+
+ streams with vector storage
+
+ These types are useful if you want a persistent buffer for formatted
+ text and you need to use it like a character array or character
+ pointer, as you get read-only access to it without copying. The
+ storage is always guaranteed to be contiguous. Writing to the
+ stream may invalidate pointers to storage.
+
+***************************************************************************/
+
+#ifndef __MAME_UTIL_VECSTREAM_H__
+#define __MAME_UTIL_VECSTREAM_H__
+
+#include <cassert>
+#include <ostream>
+#include <streambuf>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace util {
+template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
+class basic_vectorbuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+ typedef typename std::basic_streambuf<CharT, Traits>::char_type char_type;
+ typedef typename std::basic_streambuf<CharT, Traits>::int_type int_type;
+ typedef typename std::basic_streambuf<CharT, Traits>::pos_type pos_type;
+ typedef typename std::basic_streambuf<CharT, Traits>::off_type off_type;
+ typedef Allocator allocator_type;
+ typedef std::vector<char_type, Allocator> vector_type;
+
+ basic_vectorbuf(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(), m_threshold(nullptr)
+ {
+ setup();
+ }
+
+ basic_vectorbuf(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(content), m_threshold(nullptr)
+ {
+ setup();
+ }
+
+ basic_vectorbuf(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(std::move(content)), m_threshold(nullptr)
+ {
+ setup();
+ }
+
+ basic_vectorbuf(basic_vectorbuf const &that) : std::basic_streambuf<CharT, Traits>(that), m_mode(that.m_mode), m_storage(that.m_storage), m_threshold(nullptr)
+ {
+ adjust();
+ }
+
+ basic_vectorbuf(basic_vectorbuf &&that) : std::basic_streambuf<CharT, Traits>(that), m_mode(that.m_mode), m_storage(std::move(that.m_storage)), m_threshold(that.m_threshold)
+ {
+ that.clear();
+ }
+
+ vector_type const &vec() const
+ {
+ if (m_mode & std::ios_base::out)
+ {
+ if (this->pptr() > m_threshold) m_threshold = this->pptr();
+ auto const base(this->pbase());
+ auto const end(m_threshold - base);
+ if (m_storage.size() > std::make_unsigned_t<decltype(end)>(end))
+ {
+ m_storage.resize(std::make_unsigned_t<decltype(end)>(end));
+ assert(&m_storage[0] == base);
+ auto const put_offset(this->pptr() - base);
+ const_cast<basic_vectorbuf *>(this)->setp(base, base + put_offset);
+ const_cast<basic_vectorbuf *>(this)->pbump(put_offset);
+ }
+ }
+ return m_storage;
+ }
+
+ void vec(const vector_type &content)
+ {
+ m_storage = content;
+ setup();
+ }
+
+ void vec(vector_type &&content)
+ {
+ m_storage = std::move(content);
+ setup();
+ }
+
+ void clear()
+ {
+ m_storage.clear();
+ setup();
+ }
+
+ void reserve(typename vector_type::size_type size)
+ {
+ if ((m_mode & std::ios_base::out) && (m_storage.size() < size))
+ {
+ m_storage.reserve(size);
+ adjust();
+ }
+ }
+
+ basic_vectorbuf &operator=(basic_vectorbuf const &that)
+ {
+ std::basic_streambuf<CharT, Traits>::operator=(that);
+ m_mode = that.m_mode;
+ m_storage = that.m_storage;
+ m_threshold = that.m_threshold;
+ adjust();
+ return *this;
+ }
+
+ basic_vectorbuf &operator=(basic_vectorbuf &&that)
+ {
+ std::basic_streambuf<CharT, Traits>::operator=(that);
+ m_mode = that.m_mode;
+ m_storage = std::move(that.m_storage);
+ m_threshold = that.m_threshold;
+ that.clear();
+ return *this;
+ }
+
+protected:
+ pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
+ {
+ bool const in(which & std::ios_base::in);
+ bool const out(which & std::ios_base::out);
+ if ((!in && !out) ||
+ (in && out && (std::ios_base::cur == dir)) ||
+ (in && (!(m_mode & std::ios_base::in) || !this->gptr())) ||
+ (out && (!(m_mode & std::ios_base::out) || !this->pptr())))
+ {
+ return pos_type(off_type(-1));
+ }
+ maximise_egptr();
+ off_type const end((m_mode & std::ios_base::out) ? off_type(m_threshold - this->pbase()) : off_type(m_storage.size()));
+ switch (dir)
+ {
+ case std::ios_base::beg:
+ break;
+ case std::ios_base::end:
+ off += end;
+ break;
+ case std::ios_base::cur:
+ off += off_type(in ? (this->gptr() - this->eback()) : (this->pptr() - this->pbase()));
+ break;
+ default:
+ return pos_type(off_type(-1));
+ }
+ if ((off_type(0) > off) || (end < off) || ((m_mode & std::ios_base::app) && out && (end != off)))
+ return pos_type(off_type(-1));
+ if (in) this->setg(this->eback(), this->eback() + off, this->egptr());
+ if (out)
+ {
+ this->setp(this->pbase(), this->epptr());
+ this->pbump(off);
+ }
+ return pos_type(off);
+ }
+
+ virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in |std:: ios_base::out) override
+ {
+ return seekoff(off_type(pos), std::ios_base::beg, which);
+ }
+
+ virtual int_type underflow() override
+ {
+ if (!this->gptr()) return Traits::eof();
+ maximise_egptr();
+ return (this->gptr() < this->egptr()) ? Traits::to_int_type(*this->gptr()) : Traits::eof();
+ }
+
+ virtual int_type overflow(int_type ch = Traits::eof()) override
+ {
+ if (!(m_mode & std::ios_base::out)) return Traits::eof();
+ if (Traits::eq_int_type(ch, Traits::eof())) return Traits::not_eof(ch);
+ auto const put_offset(this->pptr() - this->pbase() + 1);
+ auto const threshold_offset((std::max)(m_threshold - this->pbase(), put_offset));
+ m_storage.push_back(Traits::to_char_type(ch));
+ m_storage.resize(m_storage.capacity());
+ auto const base(&m_storage[0]);
+ this->setp(base, base + m_storage.size());
+ m_threshold = base + threshold_offset;
+ if (m_mode & std::ios_base::in) this->setg(base, base + (this->gptr() - this->eback()), m_threshold);
+ this->pbump(int(put_offset));
+ return ch;
+ }
+
+ virtual int_type pbackfail(int_type ch = Traits::eof()) override
+ {
+ if (this->gptr() != this->eback())
+ {
+ if (Traits::eq_int_type(ch, Traits::eof()))
+ {
+ this->gbump(-1);
+ return Traits::not_eof(ch);
+ }
+ else if (Traits::eq(Traits::to_char_type(ch), this->gptr()[-1]))
+ {
+ this->gbump(-1);
+ return ch;
+ }
+ else if (m_mode & std::ios_base::out)
+ {
+ this->gbump(-1);
+ *this->gptr() = Traits::to_char_type(ch);
+ return ch;
+ }
+ }
+ return Traits::eof();
+ }
+
+private:
+ void setup()
+ {
+ if (m_mode & std::ios_base::out)
+ {
+ auto const end(m_storage.size());
+ m_storage.resize(m_storage.capacity());
+ if (m_storage.empty())
+ {
+ m_threshold = nullptr;
+ this->setg(nullptr, nullptr, nullptr);
+ this->setp(nullptr, nullptr);
+ }
+ else
+ {
+ auto const base(&m_storage[0]);
+ m_threshold = base + end;
+ this->setp(base, base + m_storage.size());
+ if (m_mode & std::ios_base::in) this->setg(base, base, m_threshold);
+ }
+ if (m_mode & (std::ios_base::app | std::ios_base::ate)) this->pbump(int(unsigned(end)));
+ }
+ else if (m_storage.empty())
+ {
+ this->setg(nullptr, nullptr, nullptr);
+ }
+ else if (m_mode & std::ios_base::in)
+ {
+ auto const base(&m_storage[0]);
+ this->setg(base, base, base + m_storage.size());
+ }
+ }
+
+ void adjust()
+ {
+ auto const put_offset(this->pptr() - this->pbase());
+ auto const get_offset(this->gptr() - this->eback());
+ setup();
+ if (m_mode & std::ios_base::out)
+ {
+ this->pbump(int(put_offset));
+ m_threshold = this->pptr();
+ if (m_mode & std::ios_base::in)
+ {
+ auto const base(&m_storage[0]);
+ this->setg(base, base + get_offset, m_threshold);
+ }
+ }
+ else if (m_mode & std::ios_base::in)
+ {
+ this->gbump(int(get_offset));
+ }
+ }
+
+ void maximise_egptr()
+ {
+ if (m_mode & std::ios_base::out)
+ {
+ if (m_threshold < this->pptr()) m_threshold = this->pptr();
+ if ((m_mode & std::ios_base::in) && (this->egptr() < m_threshold)) this->setg(this->eback(), this->gptr(), m_threshold);
+ }
+ }
+
+ std::ios_base::openmode m_mode;
+ mutable vector_type m_storage;
+ mutable CharT *m_threshold;
+};
+
+template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
+class basic_ivectorstream : public std::basic_istream<CharT, Traits>
+{
+public:
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+
+ basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
+ basic_ivectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
+ basic_ivectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
+
+ basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return reinterpret_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_istream<CharT, Traits>::rdbuf()); }
+ vector_type const &vec() const { return rdbuf()->vec(); }
+ void vec(const vector_type &content) { rdbuf()->vec(content); }
+ void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
+ void clear() { rdbuf()->clear(); }
+
+private:
+ basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
+};
+
+template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
+class basic_ovectorstream : public std::basic_ostream<CharT, Traits>
+{
+public:
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+
+ basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
+ basic_ovectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
+ basic_ovectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
+
+ basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return reinterpret_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_ostream<CharT, Traits>::rdbuf()); }
+
+ vector_type const &vec() const { return rdbuf()->vec(); }
+ void vec(const vector_type &content) { rdbuf()->vec(content); }
+ void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
+ void clear() { rdbuf()->clear(); }
+ void reserve(typename vector_type::size_type size) { rdbuf->reserve(size); }
+
+private:
+ basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
+};
+
+template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
+class basic_vectorstream : public std::basic_iostream<CharT, Traits>
+{
+public:
+ typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
+
+ basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
+ basic_vectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
+ basic_vectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
+
+ basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return reinterpret_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_iostream<CharT, Traits>::rdbuf()); }
+
+ vector_type const &vec() const { return rdbuf()->vec(); }
+ void vec(const vector_type &content) { rdbuf()->vec(content); }
+ void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
+ void clear() { rdbuf()->clear(); }
+ void reserve(typename vector_type::size_type size) { rdbuf->reserve(size); }
+
+private:
+ basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
+};
+
+typedef basic_ivectorstream<char> ivectorstream;
+typedef basic_ivectorstream<wchar_t> wivectorstream;
+typedef basic_ovectorstream<char> ovectorstream;
+typedef basic_ovectorstream<wchar_t> wovectorstream;
+typedef basic_vectorstream<char> vectorstream;
+typedef basic_vectorstream<wchar_t> wvectorstream;
+
+} // namespace util
+
+#endif // __MAME_UTIL_VECSTREAM_H__