This lib supports convenient output for all item-iterable container types and their composited types, and supports mutable preferences which specify the output format.
- C++ standard requirement: >= C++11
Supported container or container-like types:
std::pair
, std::tuple
,
std::array
, std::deque
, std::forward_list
, std::initializer_list
, std::list
, std::vector
,
std::set
, std::multiset
, std::unordered_set
, std::unordered_multiset
,
std::map
, std::multimap
, std::unordered_map
, std::unordered_multimap
.
For output result string, this lib supports std::string, std::wstring, or any string type specialized by template std::basic_string<CharT, Traits, Allc>.
Preferences control output style.
StringT: Some string type. e.g. std::string, std::wstring, or string type
specialized by template std::basic_string<CharT, Traits, Allc>.
DenseStyle: Bool parameter, use dense style or sparse style. Dense style means
won't output spaces between items. For example, for vector<int>{1,2,3}
,
if set DenseStyle=true, we get [1,2,3]
, or we get [1, 2, 3]
if DenseStyle=false.
Sparse style as default value.
What's more, user can modify each container's output style by this preferences
struct. For each container, there are 3 parameters to describe the style, they are
left-border, separator, right-border. For above example, default style for
vector<int>{1,2,3}
, the left-border is "["
, right-border is "]"
, and
separator is ", "
for sparse style or ","
for dense style.
You need to put at least an OstreamBaseT
into the first template parameter
as a base class, e.g. myostream::basic_ostream<std::ostream>
or
myostream::basic_ostream<std::wostringstream>
, which indicates where the
output writes to.
And you can put an optional second template parameter PreferencesT
to specify your preferred left-border, right-border and separator for each
container type, or just use the default preferences.
This class myostream::basic_ostringstream
is derived from
myostream::basic_ostream
, and has the same template parameters, a required
OstreamBaseT
and an optional PreferencesT
. But here the OstreamBaseT
should be a "stringstream type", which has a member method str()
to get a
string representing the output result. e.g.
myostream::basic_ostringstream<std::ostringstream>
is valid, but
myostream::basic_ostringstream<std::ostream>
will get a compile error.
What's more, there are useful pre-defined ostream types with default preferences:
- ostream = basic_ostream<std::ostream>
- wostream = basic_ostream<std::wostream>
- ostringstream = basic_ostringstream<std::ostringstream>
- wostringstream = basic_ostringstream<std::wostringstream>
and with dense style:
- ostream_dense = basic_ostream<std::ostream, default_preferences_by_ostream_base<std::ostream, true>>
- wostream_dense = basic_ostream<std::wostream, default_preferences_by_ostream_base<std::wostream, true>>
- ostringstream_dense = basic_ostringstream<std::ostringstream, default_preferences_by_ostream_base<std::ostringstream, true>>
- wostringstream_dense = basic_ostringstream<std::wostringstream, default_preferences_by_ostream_base<std::wostringstream, true>>
This lib overloads operator<<
for the class basic_ostream
with each
supported container type, the declaration pseudocode looks like(the key word
SomeSupportedContainerType
in the following code actually might be
std::array
, std::vector
, etc.):
template <typename OstreamBaseT, typename PreferencesT, typename... Args>
basic_ostream<OstreamBaseT, PreferencesT>& operator<<(
basic_ostream<OstreamBaseT, PreferencesT>&,
const SomeSupportedContainerType<Args...>&);
And the class basic_ostream
has more useful member functions to print multi
arguments, or a range of values designated by a pair of iterators:
// print all args in some format, e.g. on default, with a separator ", "
template <typename... Args>
basic_ostream& print(const Args&... args);
// print all args in specified format
template <typename... Args>
basic_ostream& print(const format_type& fmt, const Args&... args)
// all same with "print" except put a std::endl at last
template <typename... Args>
basic_ostream& println(const Args&... args);
// support specified format
template <typename... Args>
basic_ostream& println(const format_type& fmt, const Args&... args)
// print values in range [begin, end) in some format, e.g. on default, with a
// separator ", "
template <typename Iterator>
basic_ostream& print_range(Iterator begin, Iterator end);
// print values in range [begin, end) in format the third parameter
// "range_fmt" specified
template <typename Iterator>
basic_ostream& print_range(Iterator begin, Iterator end,
const format_type& range_fmt);
The class basic_ostringstream
is derived from basic_ostream
by public, so
it has all member functions of the latter as mentioned above. Moreover, the
former has unique member functions:
// print args into a std::vector<string_type>
template <typename... Args>
string_vector_type to_string_vector(const Args&... args);
// clear the string buffer which stores all outputs beforehand
void clear_buf();
Example:
// output to stdout
myostream::ostream mycout(std::cout.rdbuf());
std::vector<int> vi{1, 2, 3};
mycout << vi << std::endl;
std::map<std::string, std::vector<double>> msvd{
{"Alice", {95, 87.5}}, {"Bob", {79, 99.5}}};
mycout << msvd << std::endl;
// convert to std::string
myostream::ostringstream myoss;
std::vector<std::set<int>> vsi{{1, 2, 3}, {100, 200}};
myoss << vsi;
std::cout << myoss.str() << std::endl;
// use print, println
mycout.print("hello ").println("world", 123, vi);
Result:
[1, 2, 3]
{Alice: [95, 87.5], Bob: [79, 99.5]}
[{1, 2, 3}, {100, 200}]
hello world, 123, [1, 2, 3]
-
template <typename... Args> tostr(const Args&... args)
One line code to convert multiple arguments into std::string, separated by "". -
template <typename... Args> towstr(const Args&... args)
All same asmyostream::tostr
except result into std::wstring. -
template <typename... Args> ptostr(const Args&... args)
One line code to convert multiple arguments into std::string, separated by ", ". -
template <typename... Args> ptowstr(const Args&... args)
All same asmyostream::ptostr
except result into std::wstring and separated by L", ". -
template <typename... Args> tostr_dense(const Args&... args)
One line code to convert multiple arguments into std::string, separated by "". Use preferences with dense style. -
template <typename... Args> towstr_dense(const Args&... args)
All same asmyostream::tostr_dense
except result into std::wstring. Use preferences with dense style. -
template <typename... Args> ptostr_dense(const Args&... args)
One line code to convert multiple arguments into std::string, separated by ",". Use preferences with dense style. -
template <typename... Args> ptowstr_dense(const Args&... args)
All same asmyostream::ptostr_dense
except result into std::wstring and separated by L",". Use preferences with dense style.
Example:
std::vector<int> vi{1, 2, 3};
std::cout << myostream::tostr("show \"tostr\": ", vi, ", ok?") << std::endl;
std::cout << myostream::tostr_dense("show \"tostr_dense\": ", vi, ", ok?") << std::endl;
Result:
show "tostr": [1, 2, 3], ok?
show "tostr_dense": [1,2,3], ok?
Example:
std::vector<int> vi{1, 2, 3};
std::cout << myostream::ptostr("show \"ptostr\"", vi, 123) << std::endl;
Result:
show "ptostr", [1, 2, 3], 123
- Macro: MYOSTREAM_WATCH(out_stream, kv_sep, param_sep, final_delim, ...)
Print all variables in parameter...
along with their names toout_stream
in format "var1-name kv_sep var1-value param_sep var2-name kv_sep var2-value param_sep ... final_delim".
Example:
myostream::ostream mycout(std::cout.rdbuf());
#define watch(...) MYOSTREAM_WATCH(mycout, " = ", "\n", "\n\n", __VA_ARGS__)
int i = 123;
std::set<int> si{1,2,3};
watch(i, 123, si, std::set<int>{1,2,3}, "strings");
Result:
i = 123
123 = 123
si = {1, 2, 3}
std::set<int>{1,2,3} = {1, 2, 3}
"strings" = strings
- Macro: MYOSTREAM_WATCH_TO_STRING(string_type, kv_sep, param_sep, final_delim, ...)
LikeMYOSTREAM_WATCH
, but convert the result to string with typestring_type
.
Example:
#define watch(...) std::cout << MYOSTREAM_WATCH_TO_STRING(std::string, " = ", "\n", "\n\n", __VA_ARGS__)
int i = 123;
std::set<int> si{1,2,3};
std::cout << MYOSTREAM_WATCH_TO_STRING(std::string, ":", "\n", "\n----\n", i, si, 123);
std::wcout << MYOSTREAM_WATCH_TO_STRING(std::wstring, L" = ", "\n", "\n", i, si, 123);
double d = 1.4;
std::vector<int> vi(si.begin(), si.end());
watch(d, i, si, vi);
Result:
i:123
si:{1, 2, 3}
123:123
----
i = 123
si = {1, 2, 3}
123 = 123
d = 1.4
i = 123
si = {1, 2, 3}
vi = [1, 2, 3]
Install the lib to your computer:
git clone https://github.com/peacalm/myostream.git
cd myostream
mkdir build
cd build
cmake ..
make install
Package name is "MyOStream" which can be used in cmake, e.g. find_package(MyOStream REQUIRED)
.
Then happy coding with #include <myostream.h>
.
First, you need to install GoogleTest. Then enter the "build" directory like above, run:
# suppose now at directory myostream/build, then run:
cmake .. -DBUILD_TEST=TRUE
make
make test # or ctest