#include <iostream>
#include <iterator>
#include <cassert>
#include <algorithm>
#include <fstream>
#include <string>
#include <vector>
///Write a std::vector<std::string> to std::ostream
//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& w)
{
//Copy the original std::vector
std::vector<std::string> v = w;
//Preformat data
std::for_each(v.begin(),v.end(),
[&os](std::string& s)
{
//The only assertion done on the input
//Note that users nearly every use bell characters in their text inputs
assert(std::count(s.begin(),s.end(),'\b') == 0 && "Text must not contain a bell character");
std::replace(s.begin(),s.end(),' ','\b');
if (s == "</>") s = "<\b/>";
}
);
//Check data
#ifndef NDEBUG
std::for_each(v.begin(),v.end(),
[&os](const std::string& s)
{
assert(s != "</>" && "Text shoule not be '</>' anymore");
assert(std::count(s.begin(),s.end(),' ') == 0 && "Text should not contain spaces anymore");
}
);
#endif
//Write start tag
os << "<>\n";
//Write data
std::for_each(v.begin(),v.end(),
[&os](const std::string& s)
{
os << s << '\n';
}
);
//Write end tag
os << "</>";
return os;
}
///Read a std::vector<std::string> from std::ostream
//From http://richelbilderbeek.nl/CppVectorToStreamExample2.htm
std::istream& operator>>(std::istream& is, std::vector<std::string>& v)
{
//Read start tag
{
std::string s; is >> s; assert(s == std::string("<>"));
}
//Read data until end tag
while (1)
{
std::string s;
is >> s;
if (s == std::string("</>")) return is;
if (s == "<\b/>") s = "</>";
std::replace(s.begin(),s.end(),'\b',' ');
v.push_back(s);
}
}
///The data that will be written/read to/from stream
struct Data
{
Data(
const std::vector<std::string>& v = {},
const std::vector<std::string>& w = {})
: m_v(v), m_w(w) {}
std::vector<std::string> m_v;
std::vector<std::string> m_w;
};
bool operator==(const Data& lhs, const Data& rhs)
{
return lhs.m_v == rhs.m_v && lhs.m_w == rhs.m_w;
}
bool operator!=(const Data& lhs, const Data& rhs)
{
return !(lhs == rhs);
}
std::ostream& operator<<(std::ostream& os, const Data& d)
{
os << d.m_v << '\n' << d.m_w;
return os;
}
std::istream& operator>>(std::istream& is, Data& d)
{
is >> d.m_v >> d.m_w;
return is;
}
int main()
{
//Go ahead, create an entry that breaks the code!
const Data data(
{
"aahs",
"aals",
"abac",
"abas",
"</>",
" </>",
" </> ",
"_</>",
"</>_",
"</></>",
"</> </>",
"</>_</>",
"abba",
"abbe",
"abbs",
"abed",
"abet",
"abid"
}
,
{
"aahs",
"aals",
"abac",
"abas",
"</>",
" </>",
" </> ",
"_</>",
"</>_",
"</></>",
"</> </>",
"</>_</>",
"abba",
"abbe",
"abbs",
"abed",
"abet",
"abid"
}
);
const std::string filename = "tmp.txt";
//Write to file
{
std::ofstream f(filename.c_str());
f << data;
}
//Read from file
{
Data other_data;
std::ifstream f(filename.c_str());
f >> other_data;
assert(data == other_data && "Because the algorithm is excellent, this will never happen B-)");
}
}
|